import std/sugar # Declarations type FileDesc* = enum STDIN, STDOUT, STDERR IO*[T] = proc(): T func flatmap*[T, U](io: IO[T], fn: T -> IO[U]): IO[U] func lift*(fn: proc(): void): IO[void] func lift*[T](fn: proc(): T): IO[T] func join*[T](io: IO[IO[T]]): IO[T] func map*[T, U](io: IO[seq[T]], fn: T -> U): IO[seq[U]] func readstr*(stream: FileDesc): IO[string] func run*[T](io: IO[T]): T func strput*(str: string): IO[void] func to_IO*[T](val: T): IO[T] # Definitions func flatmap*[T, U](io: IO[T], fn: T -> IO[U]): IO[U] = join(io.map(fn)) func lift*(fn: proc(): void): IO[void] = proc(): void = fn() func lift*[T](fn: proc(): T): IO[T] = proc(): T = fn() func join*[T](io: IO[IO[T]]): IO[T] = io.map(run) func map*[T, U](io: IO[seq[T]], fn: T -> U): IO[seq[U]] = proc(): seq[U] = let list: seq[T] = io() if list.len == 0: @[] else: let head: T = list[0] tail: seq[T] = list[1..^1] new: IO[seq[T]] = to_IO tail @[fn(head)] & run new.map(fn) func readstr*(stream: FileDesc): IO[string] = case stream: of STDIN: lift proc(): string = readLine(stdin) of STDOUT: lift proc(): string = readLine(stdout) of STDERR: lift proc(): string = readLine(stderr) func run*[T](io: IO[T]): T = io() func strput*(str: string): IO[void] = proc(): void = echo str func to_IO*[T](val: T): IO[T] = proc(): T = val