Skip to content

Instantly share code, notes, and snippets.

@LeeeeT
Last active March 2, 2024 22:12
Show Gist options
  • Save LeeeeT/3923f6721e6d685ee1c3783b4fe7453c to your computer and use it in GitHub Desktop.
Save LeeeeT/3923f6721e6d685ee1c3783b4fe7453c to your computer and use it in GitHub Desktop.
Pure IO (does work)
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