inline def compose[A, B, R] (f: A => R) (g: B => A): B => R = x => f (g (x) )
inline def flip[A, B, R] (f: A => B => R): B => A => R = x => y => f (y) (x)
// compose[A => A1, B => B1, R] ->
// -> (f: (A => A1) => R) (g: (B => B1) => (A => A1) ): (B => B1) => R = compose (f) (g)
// -> (f: (A => A1) => R) (g: A => (B => B1) => A1 ): (B => B1) => R = compose (f) (flip (g) )
// -> (f: A / A1 ! R) flatMap (g: A => B / B1 ! A1 ): B / B1 ! R
// A / B ! R = (A => B) => R
type /[A, R] = A => R
type ![A, R] = A => R
// A / R ! R = (A => R) => R
type :#:[A, R] = A / R ! R
inline def[A, B, R, A1, B1] (f: A / A1 ! R) flatMap
(g: A => B / B1 ! A1): B / B1 ! R = compose (f) (flip (g) )
inline def[A, B, R, A1] (f: A / A1 ! R) map (g: A => B): B / A1 ! R =
compose (f) (compose (_) (g) )
inline def[A, B, R, A1] (f: A / A1 ! R)
withFilter: A / Boolean ! (A / A1 ! R) = _ => f
inline def pure[A, R] (a: A): A :#: R = _ (a)
inline def shift0[A, A1, R] (a: (A => A1) => R): A / A1 ! R = a
inline def reset0[A, R] (a: A / A ! R): R = a (identity)
inline def channel[A, B]: A / B ! (A => B) = shift0 (identity)
inline def put[A] (a: A): A :#: LazyList[A] = shift0 (a #:: _ (a) )
def loop[A, B] (f: A / B ! (A => B) ): A => B = f (loop (f) ) (_)
def fib () = loop (for {
(x, y) <- channel[(BigInt, BigInt), LazyList[BigInt]]
_ <- put (x) } yield (y, x + y) ) (1, 1)
object Test {
def main(arg: Array[String]): Unit =
for (n <- fib().take(1000)) println(n)
}