5.6. Call Pattern

A call pattern allows a call to be made within a pattern match.

A pattern x( P0 ,, Pn ), is matched against a value v by calling x.unapply(v), and matching each value published by that call against the tuple pattern ( P0 ,, Pn ). If there is only one pattern P, then P is matched on its own, instead of using a tuple pattern. If there are no patterns, a wildcard pattern is used.

If x.unapply(v) halts silently, or halts without producing any matching values, then the match fails.

If multiple values are published and successfully match, then a multimatch occurs: the entire pattern succeeds multiple times. In a function call, the matching clause is executed multiple times, once for each match. In a sequential combinator, the right hand side is executed multiple times, once for each match. In a pruning combinator, one of the matches is chosen arbitrarily.

Warning

When an as pattern contains a call pattern, counterintuitive behavior may result. The as pattern will capture the value fragment before matching, so if a call pattern changes the value fragment, that change will not be captured by the as pattern. Avoid using call patterns within as patterns unless the value fragment is guaranteed to remain unchanged.

5.6.1. Syntax

[43]CallPattern::= Variable ( Pattern , , Pattern )  

5.6.2. Type

When a call pattern is matched against a type S, the unapply member of the type S must have the function type lambda (T) :: (T0 ,, Tn), where S is a subtype of T. Then each argument pattern Pi is matched against the corresponding type Ti, producing typing contexts Γi. The typing context produced by the whole match is the union of the contexts Γi.

5.6.3. Examples

Trees
{- 
   Build up a small binary tree, then use call patterns to deconstruct the tree and extract its contents.   
-}

type Tree = Node(_,_,_) | Empty()

val l = Node(Empty(), 0, Empty())
val r = Node(Empty(), 2, Empty())
val t = Node(l,1,r)

t >Node(l,j,r)>
l >Node(_,i,_)>
r >Node(_,k,_)>
( i | j | k )

{-
OUTPUT:PERMUTABLE
0
1
2
-}

Integer square root
{- 
   A user-defined call pattern match, using a record with an unapply member.
   
   The integer square root function, isqrt, returns the square root of a
   perfect square, and halts on any input that is not a perfect square.
   
   isqrt is then used to define a value 'square' that matches perfect squares.
-}

def isqrt(n) =
  if (n <: 0) 
    then stop
    else (
      val root = Floor(n ** 0.5)
      if (n = root*root) 
        then root 
        else stop
    )

val square = {. unapply = isqrt .}

each([9, 12, 16, 24, 25]) >square(n)> n

{-
OUTPUT:PERMUTABLE:
3
4
5
-}

Factoring Using Multimatch
{- 
   A user-defined call pattern match, using a record with an unapply member.
   
   The factors function publishes all nontrivial positive factors of its argument n 
   (any factor greater than 1 and less than n) 
   
   factors is then used to define a value 'multipleOf' that matches all
   nontrivial positive factors of an integer.
-}

def factors(n) if (n <: 0) = factors(-n)
def factors(n) = for(2, n/2 + 1) >i> Ift(n % i = 0) >> i

val multipleOf = {. unapply = factors .}

30 >multipleOf(n)> n

{-
OUTPUT:PERMUTABLE:
2
3
5
6
10
15
-}

5.6.4. Related Links

Related Tutorial Sections