/* Input/Output

A sample code of `stream`:

```
import ck/io

fun main()
  read-stdin().stream
    val a = sint().unjust
    val b = sint().unjust
    val c = sint().unjust
    val s = sstring()
    (a + b + c).print
    " ".print
    s.println
```
\/
*/
module io

import path
import file
import readline

// *Reasonably* fast stream
pub linear effect streamck/io/stream: HX1
  fun read-untilck/io/read-until: (p : (char) -> bool) -> stream string(pp: (char) -> bool: charstd/core/types/char: V -> boolstd/core/types/bool: V): stringstd/core/types/string: V
  fun skip-untilck/io/skip-until: (p : (char) -> bool) -> stream ()(pp: (char) -> bool: charstd/core/types/char: V -> boolstd/core/types/bool: V): (std/core/types/(): V)std/core/types/(): V

pub fun skip-whitespacesck/io/skip-whitespaces: () -> stream ()(): streamck/io/stream: HX1 (std/core/types/(): V)std/core/types/(): V
  skip-untilck/io/skip-until: (p : (char) -> bool) -> stream ()(is-whitestd/core/is-white: (c : char) -> bool)

// Read a string from a stream.
// This function first skips whitespaces, and then reads characters until
// reaching whitespace
pub fun sstringck/io/sstring: () -> stream string(): streamck/io/stream: HX1 stringstd/core/types/string: V
  skip-whitespacesck/io/skip-whitespaces: () -> stream ()()
  read-untilck/io/read-until: (p : (char) -> bool) -> stream string(fn(cc: char) { !std/core/types/(!).1: (b : bool) -> boolcc: char.is-whitestd/core/is-white: (c : char) -> bool })

// Read an integer from a stream
pub fun sintck/io/sint: () -> <div,stream> maybe<int>(): <std/core/types/(<>): Edivstd/core/types/div: X,streamck/io/stream: HX1> maybestd/core/types/maybe: V -> V<intstd/core/types/int: V>
  skip-whitespacesck/io/skip-whitespaces: () -> stream ()()
  sstringck/io/sstring: () -> stream string().parse-intstd/core/parse-int: (s : string, hex : ?bool) -> maybe<int>

pub fun streamck/io/stream: forall<a,e> (s : vector<char>, action : () -> <stream,div|e> a) -> <div|e> a(^ss: vector<char>: vectorstd/core/types/vector: V -> V<charstd/core/types/char: V>, actionaction: () -> <stream,div|$594> $593: () -> <streamck/io/stream: HX1,divstd/core/types/div: X|std/core/types/(<|>): (X, E) -> Eee: E> aa: V): <divstd/core/types/div: X|std/core/types/(<|>): (X, E) -> Eee: E> aa: V
  varstd/core/hnd/local-var: forall<a,b,e,h> (init : a, action : (l : local-var<h,a>) -> <local<h>|e> b) -> <local<h>|e> b cursorstd/core/types/local-scope: forall<a,e> (action : forall<h> () -> <local<h>|e> a) -> e a := 0
  with handlerhandler: (() -> <stream,div,local<$598>|$594> $593) -> <div,local<$598>|$594> $593
    fun skip-untilskip-until: (p : (char) -> bool) -> <div,local<$598>|$594> ()(pp: (char) -> bool)
      fun looploop: () -> <div,local<$598>> ()(): <std/core/types/(<>): Elocalstd/core/types/local: H -> X<__w-l50-c26: H>,divstd/core/types/div: X> (std/core/types/(): V)std/core/types/(): V
        match ss: vector<char>.atstd/core/at: forall<a> (v : vector<a>, index : int) -> maybe<a>(cursorcursor: int)
          Juststd/core/types/Just: forall<a> (value : a) -> maybe<a>(cc: char) | pp: (char) -> bool(cc: char) ->
            cursorcursor: local-var<$598,int> :=std/core/types/local-set: forall<a,e,h> (v : local-var<h,a>, assigned : a) -> <local<h>|e> () cursorcursor: int +std/core/(+).4: (x : int, y : int) -> int 1
            looploop: () -> <local<$598>,div> ()()
          _ -> (std/core/types/(): ())std/core/types/(): ()
      looploop: () -> <div,local<$598>> ()()
    fun read-untilread-until: (p : (char) -> bool) -> <div,local<$598>|$594> string(pp: (char) -> bool)
      fun looploop: (res : string) -> <div,local<$598>> string(resres: string): <std/core/types/(<>): Elocalstd/core/types/local: H -> X<__w-l58-c29: H>,divstd/core/types/div: X> stringstd/core/types/string: V
        match ss: vector<char>.atstd/core/at: forall<a> (v : vector<a>, index : int) -> maybe<a>(cursorcursor: int)
          Juststd/core/types/Just: forall<a> (value : a) -> maybe<a>(cc: char) | pp: (char) -> bool(cc: char) ->
            cursorcursor: local-var<$598,int> :=std/core/types/local-set: forall<a,e,h> (v : local-var<h,a>, assigned : a) -> <local<h>|e> () cursorcursor: int +std/core/(+).4: (x : int, y : int) -> int 1
            looploop: (res : string) -> <local<$598>,div> string(resres: string ++std/core/(++).1: (x : string, y : string) -> string cc: char.stringstd/core/string: (c : char) -> string)
          _ -> resres: string
      looploop: (res : string) -> <div,local<$598>> string("")
  actionaction: () -> <stream,div|$594> $593()

pub fun streamck/io/stream.1: forall<a,e> (s : string, action : () -> <stream,div|e> a) -> <div|e> a(^ss: string: stringstd/core/types/string: V, actionaction: () -> <stream,div|$1086> $1085: () -> <streamck/io/stream: HX1,divstd/core/types/div: X|std/core/types/(<|>): (X, E) -> Eee: E> aa: V): <divstd/core/types/div: X|std/core/types/(<|>): (X, E) -> Eee: E> aa: V
  ss: string.vectorstd/core/vector.1: (s : string) -> vector<char>.streamck/io/stream: forall<a,e> (s : vector<char>, action : () -> <stream,div|e> a) -> <div|e> a(actionaction: () -> <stream,div|$1086> $1085)

pub fun read-stdinck/io/read-stdin: () -> <exn,fsys> string(): <std/core/types/(<>): Eexnstd/core/exn: HX,fsysstd/core/fsys: X> stringstd/core/types/string: V
  read-text-filestd/os/file/read-text-file: (path : path) -> <exn,fsys> string(pathstd/os/path/path: (s : string) -> path("/dev/stdin"))

// Parse integers separated by whitespaces
pub fun parse-intsck/io/parse-ints: (s : string) -> exn list<int>(ss: string: stringstd/core/types/string: V): exnstd/core/exn: HX liststd/core/list: V -> V<intstd/core/types/int: V>
  ss: string.splitstd/core/split.1: (s : string, sep : string) -> list<string>(" ").mapstd/core/map.5: forall<a,b,e> (xs : list<a>, f : (a) -> e b) -> e list<b>(fn(s's': string) { s's': string.parse-intstd/core/parse-int: (s : string, hex : ?bool) -> maybe<int>.unjuststd/core/unjust: forall<a> (m : maybe<a>) -> exn a })

// Read integers from standard input.
// Warning: if a line to be read contains more than 1,022 characters,
// this function does not work properly. Use `read-stdin` and `parse-ints` instead
pub fun read-intsck/io/read-ints: () -> <console,exn> list<int>(): <std/core/types/(<>): Econsolestd/core/console: X,exnstd/core/exn: HX> liststd/core/list: V -> V<intstd/core/types/int: V>
  readlinestd/os/readline/readline: () -> <console,exn> string().parse-intsck/io/parse-ints: (s : string) -> exn list<int>

pub fun printlnck/io/println: (l : list<int>, sep : ?string) -> console ()(ll: list<int>: liststd/core/list: V -> V<intstd/core/types/int: V>, sepsep: ?string: stringstd/core/types/optional: V -> V = " "): consolestd/core/console: X (std/core/types/(): V)std/core/types/(): V
  varstd/core/hnd/local-var: forall<a,b,e,h> (init : a, action : (l : local-var<h,a>) -> <local<h>|e> b) -> <local<h>|e> b firststd/core/types/local-scope: forall<a,e> (action : forall<h> () -> <local<h>|e> a) -> e a := Truestd/core/types/True: bool
  foreachstd/core/foreach: forall<a,e> (xs : list<a>, action : (a) -> e ()) -> e () (ll: list<int>) fn(xx: int)
    if firstfirst: bool then firstfirst: local-var<$346,bool> :=std/core/types/local-set: forall<a,e,h> (v : local-var<h,a>, assigned : a) -> <local<h>|e> () Falsestd/core/types/False: bool
    else sepsep: string.printstd/core/print: (s : string) -> console ()
    xx: int.printstd/core/print.1: (i : int) -> console ()
  "".printlnstd/core/println: (s : string) -> console ()