Skip to content

Instantly share code, notes, and snippets.

@LeeeeT
Created February 24, 2024 11:43
Show Gist options
  • Save LeeeeT/3600fa17bf98af991cf9b28173b25774 to your computer and use it in GitHub Desktop.
Save LeeeeT/3600fa17bf98af991cf9b28173b25774 to your computer and use it in GitHub Desktop.
Laziness complete
from __future__ import annotations
from collections.abc import Callable, Iterator
from typing import Protocol, cast
type Lazy[Value] = Callable[[], Value]
def lazify[Value](value: Value) -> Lazy[Value]:
return lambda: value
class Option[Value](Protocol):
def __call__[Return](self, nothing_case: Lazy[Return], some_case: Lazy[Callable[[Lazy[Value]], Lazy[Return]]]) -> Lazy[Return]:
...
@lazify
def nothing[Value, Return](nothing_case: Lazy[Return], some_case: Lazy[Callable[[Lazy[Value]], Lazy[Return]]]) -> Lazy[Return]:
return nothing_case
@lazify
def some[Value](value: Lazy[Value]) -> Lazy[Option[Value]]:
@lazify
def option[Return](nothing_case: Lazy[Return], some_case: Lazy[Callable[[Lazy[Value]], Lazy[Return]]]) -> Lazy[Return]:
return lambda: some_case()(value)()
return option
class Natural(Protocol):
def __call__[Return](self, zero_case: Lazy[Return], successor_case: Lazy[Callable[[Lazy[Natural]], Lazy[Return]]]) -> Lazy[Return]:
...
@cast(Callable[[Natural], Lazy[Natural]], lazify)
def zero[Return](zero_case: Lazy[Return], successor_case: Lazy[Callable[[Lazy[Natural]], Lazy[Return]]]) -> Lazy[Return]:
return zero_case
@lazify
def successor(number: Lazy[Natural]) -> Lazy[Natural]:
@lazify
def successor[Return](zero_case: Lazy[Return], successor_case: Lazy[Callable[[Lazy[Natural]], Lazy[Return]]]) -> Lazy[Return]:
return lambda: successor_case()(number)()
return successor
one = successor()(zero)
two = successor()(one)
three = successor()(two)
@lazify
def int_to_natural(int: Lazy[int]) -> Lazy[Natural]:
return lambda: successor()(lambda: int_to_natural()(lambda: int() - 1)())() if int() else zero()
@lazify
def natural_to_int(natural: Lazy[Natural]) -> Lazy[int]:
@lazify
def natural_successor_case(natural_predessor: Lazy[Natural]) -> Lazy[int]:
return lambda: natural_to_int()(natural_predessor)() + 1
return lambda: natural()(lambda: 0, natural_successor_case)()
class Stream[Value](Protocol):
def __call__[Return](self, consumer: Lazy[Callable[[Lazy[Value], Lazy[Stream[Value]]], Lazy[Return]]]) -> Lazy[Return]:
...
@lazify
def stream_of[Value](value: Lazy[Value]) -> Lazy[Stream[Value]]:
@lazify
def stream[Return](consumer: Lazy[Callable[[Lazy[Value], Lazy[Stream[Value]]], Lazy[Return]]]) -> Lazy[Return]:
return lambda: consumer()(value, lambda: stream_of()(value)())()
return stream
class List[Value](Protocol):
def __call__[Return](self, empty_case: Lazy[Return], constructor_case: Lazy[Callable[[Lazy[Value], Lazy[List[Value]]], Lazy[Return]]]) -> Lazy[Return]:
...
@lazify
def empty[Value, Return](empty_case: Lazy[Return], constructor_case: Lazy[Callable[[Lazy[Value], Lazy[List[Value]]], Lazy[Return]]]) -> Lazy[Return]:
return empty_case
@lazify
def constructor[Value](head: Lazy[Value], tail: Lazy[List[Value]]) -> Lazy[List[Value]]:
@lazify
def list[Return](empty_case: Lazy[Return], constructor_case: Lazy[Callable[[Lazy[Value], Lazy[List[Value]]], Lazy[Return]]]) -> Lazy[Return]:
return lambda: constructor_case()(head, tail)()
return list
@lazify
def take[Value](number: Lazy[Natural], stream: Lazy[Stream[Value]]) -> Lazy[List[Value]]:
@lazify
def number_successor_case(number_predessor: Lazy[Natural]) -> Lazy[List[Value]]:
@lazify
def consumer(head: Lazy[Value], tail: Lazy[Stream[Value]]) -> Lazy[List[Value]]:
return lambda: constructor()(head, lambda: take()(number_predessor, tail)())()
return lambda: stream()(consumer)()
return lambda: number()(empty, number_successor_case)()
@lazify
def stream_to_list[Value](stream: Lazy[Stream[Value]]) -> Lazy[List[Value]]:
@lazify
def consumer(head: Lazy[Value], tail: Lazy[Stream[Value]]) -> Lazy[List[Value]]:
return lambda: constructor()(head, lambda: stream_to_list()(tail)())()
return lambda: stream()(consumer)()
@lazify
def safe_next[Value](iterator: Lazy[Iterator[Lazy[Value]]]) -> Lazy[Option[Value]]:
def option() -> Option[Value]:
try:
return some()(next(iterator()))()
except StopIteration:
return nothing()
return option
@lazify
def iterator_to_list[Value](iterator: Lazy[Iterator[Lazy[Value]]]) -> Lazy[List[Value]]:
@lazify
def safe_next_some_case(value: Lazy[Value]) -> Lazy[List[Value]]:
return lambda: constructor()(value, lambda: iterator_to_list()(iterator)())()
return lambda: safe_next()(iterator)()(empty, safe_next_some_case)()
@lazify
def list_to_iterator[Value](list: Lazy[List[Value]]) -> Lazy[Iterator[Lazy[Value]]]:
@lazify
def list_constructor_case(head: Lazy[Value], tail: Lazy[List[Value]]) -> Lazy[Iterator[Lazy[Value]]]:
def iterator() -> Iterator[Lazy[Value]]:
yield head
yield from list_to_iterator()(tail)()
return iterator
return lambda: list()(lambda: iter(()), list_constructor_case)()
stream_of_ones = stream_of()(one)
three_ones = take()(three, stream_of_ones)
for n in list_to_iterator()(three_ones)():
print(natural_to_int()(n)())
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment