Last active
March 2, 2024 22:12
-
-
Save LeeeeT/3923f6721e6d685ee1c3783b4fe7453c to your computer and use it in GitHub Desktop.
Pure IO (does work)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import sys | |
from collections.abc import Callable, Iterator | |
from functools import cache | |
type Lazy[T] = Callable[[], T] | |
type Stream[T] = Lazy[tuple[T, Stream[T]]] | |
def iterator_to_stream[T](iterator: Iterator[T]) -> Stream[T]: | |
return cache(lambda: (next(iterator), iterator_to_stream(iterator))) | |
type List[T] = Lazy[None | tuple[T, List[T]]] | |
list_empty = lambda: None | |
def list_identity[T](value: T) -> List[T]: | |
return lambda: (value, list_empty) | |
def list_to_iterator[T](list: List[T]) -> Iterator[T]: | |
def iterator() -> Iterator[T]: | |
match list(): | |
case None: | |
return | |
case head, tail: | |
yield head | |
yield from list_to_iterator(tail) | |
return iterator() | |
def iterator_to_list[T](iterator: Iterator[T]) -> List[T]: | |
def list() -> None | tuple[T, List[T]]: | |
try: | |
return next(iterator), iterator_to_list(iterator) | |
except StopIteration: | |
pass | |
return list | |
def list_add[T](first: List[T], second: List[T]) -> List[T]: | |
def iterator() -> Iterator[T]: | |
yield from list_to_iterator(first) | |
yield from list_to_iterator(second) | |
return iterator_to_list(iterator()) | |
type IO[T] = Callable[[Stream[str]], tuple[Lazy[T], List[str], Stream[str]]] | |
def io_identity[T](value: T) -> IO[T]: | |
return lambda stdin: (lambda: value, list_empty, stdin) | |
def io_map[From, To](io: IO[From], function: Callable[[From], To]) -> IO[To]: | |
return lambda stdin: (lambda: function(io(stdin)[0]()), io(stdin)[1], io(stdin)[2]) | |
def io_join[T](io: IO[IO[T]]) -> IO[T]: | |
return lambda stdin: (lambda: io(stdin)[0]()(io(stdin)[2])[0](), lambda: list_add(io(stdin)[1], io(stdin)[0]()(io(stdin)[2])[1])(), lambda: io(stdin)[0]()(io(stdin)[2])[2]()) | |
def io_bind[From, To](io: IO[From], function: Callable[[From], IO[To]]) -> IO[To]: | |
return io_join(io_map(io, function)) | |
def io_then[A, B](first: IO[A], second: IO[B]) -> IO[B]: | |
return io_bind(first, lambda _: second) | |
def io_run[T](io: IO[T]) -> T: | |
stdin = iterator_to_stream(map(str.strip, sys.stdin)) | |
value, stdout, stdin = io(stdin) | |
sys.stdout.writelines(list_to_iterator(stdout)) | |
return value() | |
def get_line(stdin: Stream[str]) -> tuple[Lazy[str], List[str], Stream[str]]: | |
return (lambda: stdin()[0], list_empty, lambda: stdin()[1]()) | |
def put_str(str: str) -> IO[None]: | |
return lambda stdin: (lambda: None, list_identity(str), stdin) | |
def put_str_ln(str: str) -> IO[None]: | |
return put_str(str + '\n') | |
main = \ | |
io_then(put_str_ln('what\'s your name?'), | |
io_bind(get_line, lambda name: | |
put_str_ln(f'hi, {name}!') | |
)) | |
io_run(main) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment