11.3. idioms: Higher-order Orc programming idioms.

Higher-order Orc programming idioms. Many of these are standard functional-programming combinators borrowed from Haskell or Scheme.

11.3.1. curry

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)


            

11.3.2. curry3

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)


            

11.3.3. uncurry

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)


            

11.3.4. uncurry3

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)


            

11.3.5. flip

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)


            

11.3.6. constant

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


            

11.3.7. defer

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)


            

11.3.8. defer2

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)


            

11.3.9. ignore

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()


            

11.3.10. ignore2

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()


            

11.3.11. compose

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))


            

11.3.12. while

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


            

11.3.13. repeat

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))


            

11.3.14. fork

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)


            

11.3.15. forkMap

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)


            

11.3.16. seq

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)


            

11.3.17. seqMap

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)


            

11.3.18. join

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


            

11.3.19. joinMap

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


            

11.3.20. alt

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)


            

11.3.21. altMap

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)


            

11.3.22. por

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)
  )


            

11.3.23. pand

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)
  )


            

11.3.24. collect

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()