Receiving, Where It Shines
The previous section showed the value[variable] receive command — but it didn’t feel essential.
Let’s now explore a use-case where this command really shines: polling values from an
infinite sequence.
You may remember the Sequence<a> type from earlier. Here’s the definition again:
type Sequence<a> = iterative choice {
.close => !,
.next => (a) self,
}
A Sequence can generate an unbounded number of values, one by one, and eventually be closed.
A Fibonacci sequence, as a value
Let’s start by building a sequence of Fibonacci numbers.
dec Fibonacci : Sequence<Nat>
def Fibonacci =
let (a) b = (0) 1
in begin case {
.close => !
.next =>
let (a) b = (b) Nat.Add(a, b)
in (a) loop
}
The internal state of the sequence is a pair (a) b. On each .next, we emit a and update
the pair. This is a clean and elegant use of corecursive iteration, as we’ve covered it in the
section on iterative types.
So far so good — but how do we use this value?
Goal: print the first 30 Fibonacci numbers
Let’s say we want to print the first 30 Fibonacci numbers to the terminal.
That means:
- Repeating an action 30 times,
- Receiving a number from the sequence each time,
- Converting it to a string,
- Sending it to the output.
We’ll need a way to loop exactly 30 times. But there’s a catch: In Par,
looping is only possible on recursive types. There’s no built-in recursion on Nat, so we need
to convert the number 30 into a recursive.
Good news: there’s a built-in helper for that! It’s called Nat.Repeat, here’s its type:
dec Nat.Repeat : [Nat] recursive either {
.end!,
.step self,
}
Calling Nat.Repeat(30) gives us a recursive value that can be stepped through exactly 30 times.
Precisely what we need.
Now for the second part: printing.
Console output
Par comes with a built-in definition for working with standard output:
def Console.Open : Console
The Console type itself is defined like this:
type Console = iterative choice {
.close => !,
.print(String) => self,
}
You can think of it as a “sink” object that receives strings and sends them to the terminal.
Much like String.Builder, but the output appears directly in your console.
Let’s tie it all together!
def Program: ! = do {
let console = Console.Open
let fib = Fibonacci
Nat.Repeat(30).begin.case {
.end! => {}
.step remaining => {
fib.next[n]
console.print(Int.ToString(n))
remaining.loop
}
}
fib.close
console.close
} in !
Here’s what’s happening:
Nat.Repeat(30)becomes the subject of the.beginand.casecommands.- In each
.step, we receive a number from thefibsequence using thefib.next[n]command. - We convert it to a string using
Int.ToString(n)and print it to the console. - Then we
loop.
The fib.next[n] line is where receive command truly shines. It receives the payload
of the .next branch — a number — and updates fib to the rest of the sequence. Note, that
it’s a combination of two commands: a selection and a receive.
Once done, we close both the sequence and the console. We must, they are linear.