Higher-order Orc programming idioms. Many of these are standard functional-programming combinators borrowed from Haskell or Scheme.
def curry[A,B,C](lambda (A,B) :: C) :: lambda(A) :: lambda(B) :: C
Curry a function of two arguments.
Implementation.
def curry[A,B,C](lambda (A,B) :: C) :: lambda(A) :: lambda(B) :: C def curry(f) = lambda(x) = lambda(y) = f(x,y)
def curry3[A,B,C,D](lambda (A,B,C) :: D) :: lambda(A) :: lambda(B) :: lambda(C) :: D
Curry a function of three arguments.
Implementation.
def curry3[A,B,C,D](lambda (A,B,C) :: D) :: lambda(A) :: lambda(B) :: lambda(C) :: D def curry3(f) = lambda(x) = lambda(y) = lambda(z) = f(x,y,z)
def uncurry[A,B,C](lambda (A) :: lambda(B) :: C) :: lambda(A, B) :: C
Uncurry a function of two arguments.
Implementation.
def uncurry[A,B,C](lambda (A) :: lambda(B) :: C) :: lambda(A, B) :: C def uncurry(f) = lambda(x,y) = f(x)(y)
def uncurry3[A,B,C,D](lambda (A)(B)(C) :: D) :: lambda(A,B,C) :: D
Uncurry a function of three arguments.
Implementation.
def uncurry3[A,B,C,D](lambda (A) :: lambda(B) :: lambda(C) :: D) :: lambda(A,B,C) :: D def uncurry3(f) = lambda(x,y,z) = f(x)(y)(z)
def flip[A,B,C](lambda (A, B) :: C) :: lambda(B, A) :: C
Flip the order of parameters of a two-argument function.
Implementation.
def flip[A,B,C](lambda (A, B) :: C) :: lambda(B, A) :: C def flip(f) = lambda(x,y) = f(y,x)
def constant[A](A) :: lambda() :: A
Create a function which returns a constant value.
Implementation.
def constant[A](A) :: lambda() :: A def constant(x) = lambda() = x
def defer[A,B](lambda (A) :: B, A) :: lambda() :: B
Given a function and its argument, return a thunk which applies the function.
Implementation.
def defer[A,B](lambda (A) :: B, A) :: lambda() :: B def defer(f, x) = lambda() = f(x)
def defer2[A,B,C](lambda (A,B) :: C, A, B) :: lambda() :: C
Given a function and its arguments, return a thunk which applies the function.
Implementation.
def defer2[A,B,C](lambda (A,B) :: C, A, B) :: lambda() :: C def defer2(f, x, y) = lambda() = f(x, y)
def ignore[A](lambda () :: A) :: lambda(Top) :: B
From a function of no arguments, create a function of one argument, which is ignored.
Implementation.
def ignore[A](lambda () :: A) :: lambda(Top) :: A def ignore(f) = lambda(_) = f()
def ignore2[A,B,C](lambda () :: C) :: lambda(A, B) :: C
From a function of no arguments, create a function of two arguments, which are ignored.
Implementation.
def ignore2[A,B,C](lambda () :: C) :: lambda(A, B) :: C def ignore2(f) = lambda(_, _) = f()
def compose[A,B,C](lambda (B) :: C, lambda (A) :: B) :: lambda(A) :: C
Compose two single-argument functions.
Implementation.
def compose[A,B,C](lambda (B) :: C, lambda (A) :: B) :: lambda (A) :: C def compose(f,g) = lambda(x) = f(g(x))
def while[A](lambda (A) :: Boolean, lambda (A) :: A) :: lambda(A) :: A
Iterate a function while a predicate is satisfied, publishing each value passed to the function.
Example:
-- Publishes: 0 1 2 3 4 5 while( lambda (n) = (n <= 5), lambda (n) = n+1 )(0)
Implementation.
def while[A](lambda (A) :: Boolean, lambda (A) :: A) :: lambda(A) :: A def while(p,f) = def loop(A) :: A def loop(x) = Ift(p(x)) >> ( x | loop(f(x)) ) loop
def repeat[A](lambda () :: A) :: A
Call a function sequentially, publishing each value returned by the function.
The expression repeat(f)
is equivalent to
the infinite expression f() >x> ( x | f() >x> ( x | f() >x> ... ) )
Implementation.
def repeat[A](lambda () :: A) :: A def repeat(f) = f() >x> (x | repeat(f))
def fork[A](List[lambda () :: A]) :: A
Call a list of functions in parallel, publishing all values published by the functions.
The expression fork([f,g,h])
is equivalent to
the expression f() | g() | h()
Implementation.
def fork[A](List[lambda () :: A]) :: A def fork([]) = stop def fork(p:ps) = p() | fork(ps)
def forkMap[A,B](lambda (A) :: B, List[A]) :: B
Apply a function to a list in parallel, publishing all values published by the applications.
The expression forkMap(f, [a,b,c])
is equivalent to
the expression f(a) | f(b) | f(c)
This function can be thought of as the following composition
fork(map(curry(defer)(f), xs))
(hence the name forkMap
).
It maps f
over the list and then forks each of the
resulting computations.
Implementation.
def forkMap[A,B](lambda (A) :: B, List[A]) :: B def forkMap(f, []) = stop def forkMap(f, x:xs) = f(x) | forkMap(f, xs)
def seq[A](List[lambda () :: A]) :: Signal
Call a list of functions in sequence, publishing a signal whenever the last function publishes. The actual publications of the given functions are not published.
The expression seq([f,g,h])
is equivalent to
the expression f() >> g() >> h() >> signal
Implementation.
def seq[A](List[lambda () :: A]) :: Signal def seq([]) = signal def seq(p:ps) = p() >> seq(ps)
def seqMap[A,B](lambda (A) :: B, List[A]) :: Signal
Apply a function to a list in sequence, publishing a signal whenever the last application publishes. The actual publications of the given functions are not published.
The expression seqMap(f, [a,b,c])
is equivalent to
the expression f(a) >> f(b) >> f(c) >> signal
This function can be thought of as the following composition
seq(map(curry(defer)(f), xs))
(hence the name seqMap
).
It maps f
over the list and then runs each of the
resulting computations in sequence. This is analogous to foreach
in Scala
or iterate
in OCaml.
Implementation.
def seqMap[A,B](lambda (A) :: B, List[A]) :: Signal def seqMap(f, []) = signal def seqMap(f, x:xs) = f(x) >> seqMap(f, xs)
def join[A](List[lambda () :: A]) :: Signal
Call a list of functions in parallel and publish a signal once all functions have completed.
The expression join([f,g,h])
is equivalent to
the expression (f(), g(), h()) >> signal
Implementation.
def join[A](List[lambda () :: A]) :: Signal def join([]) = signal def join(p:ps) = (p(), join(ps)) >> signal
def joinMap[A](lambda (A) :: Top, List[A]) :: Signal
Apply a function to a list in parallel and publish a signal once all applications have completed.
The expression joinMap(f, [a,b,c])
is equivalent to
the expression (f(a), f(b), f(c)) >> signal
This function can be thought of as the following composition
join(map(curry(defer)(f), xs))
(hence the name joinMap
).
Implementation.
def joinMap[A](lambda (A) :: Top, List[A]) :: Signal def joinMap(f, []) = signal def joinMap(f, x:xs) = (f(x), joinMap(f, xs)) >> signal
def alt[A](List[lambda () :: A]) :: A
Call each function in the list until one of them publishes (choosing the publishing alternative).
The expression alt([f,g,h])
is equivalent to
the expression f() ; g() ; h()
Implementation.
def alt[A](List[lambda () :: A]) :: A def alt([]) = stop def alt(p:ps) = p() ; alt(ps)
def altMap[A,B](lambda (A) :: B, List[A]) :: B
Apply the function to each element in the list until one publishes.
The expression altMap(f, [a,b,c])
is equivalent to
the expression f(a) ; f(b) ; f(c)
This function can be thought of as the following composition
alt(map(curry(defer)(f), xs))
(hence the name altMap
).
Implementation.
def altMap[A,B](lambda (A) :: B, List[A]) :: B def altMap(f, []) = stop def altMap(f, x:xs) = f(x) ; altMap(f, xs)
def por(List[lambda () :: Boolean]) :: Boolean
Parallel or. Execute a list of boolean functions in parallel, publishing a value as soon as possible, and killing any unnecessary ongoing computation.
Implementation.
def por(List[lambda () :: Boolean]) :: Boolean def por([]) = false def por(p:ps) = Let( val b1 = p() val b2 = por(ps) Ift(b1) >> true | Ift(b2) >> true | (b1 || b2) )
def pand(List[lambda () :: Boolean]) :: Boolean
Parallel and. Execute a list of boolean functions in parallel, publishing a value as soon as possible, and killing any unnecessary ongoing computation.
Implementation.
def pand(List[lambda () :: Boolean]) :: Boolean def pand([]) = true def pand(p:ps) = Let( val b1 = p() val b2 = pand(ps) Iff(b1) >> false | Iff(b2) >> false | (b1 && b2) )
def collect[A](lambda () :: A) :: List[A]
Run a function, collecting all publications in a list. Publish the list when the function halts.
Example:
-- Publishes: [signal, signal, signal, signal, signal] collect(defer(signals, 5))
Implementation.
def collect[A](lambda () :: A) :: List[A] def collect(p) = val b = Channel[A]() p() >x> b.put(x) >> stop ; b.getAll()