blob: 790a4ccf44c9e1a22abfbfc806f9c7e51184e83d [file] [log] [blame] [edit]
-- This is a standalone example that doesn't make use of the gum
-- library. As such it needs to define its own opaque environment type.
type Env
-- The environment is also required to print to the standard output.
show_u32 : (Env, U32) -> Env
show_string : (Env, String) -> Env
-- Newline is defined internally.
newline : Env -> Env
newline env = show_string(env, "\n")
-- This is a relatively simple definition of an iterator.
--
-- As Cogent does not support any form of iteration or recursion
-- internally we need to rely on the ability for C to perform the loop.
--
-- For an iterator to terminate starting with a given loop value, the
-- IterStep must, after some number of repeated applications of itself
-- to its own result, eventually return a value for which the
-- IterCondition will produce a Stop.
-- A step determines the action that turns one loop value into another.
-- It is effectively the 'loop body'
type IterStep a = a -> a
-- A condition determines whether a given loop value must be passed
-- though the step or the loop should complete.
type IterCondition a = a! -> <Continue | Stop>
type Iterator a = #
{ curr : a
, step : IterStep a
, condition : IterCondition a
}
-- A simple constructor for a stack-allocated iterator
iterator : all (a) . (a, IterStep a, IterCondition a) -> Iterator a
iterator (curr, step, condition) = #{ curr, step, condition }
-- Execute the iterator to completion and produce the value for which
-- the IterCondition returned Stop
iterate : all (a) . Iterator a -> a
-- A FizzBuzz iterator
fizzbuzz : (Env, U32) -> Iterator (Env, U32, U32)
fizzbuzz (env, last) =
-- We track the environment, current number, and the last number to
-- show.
let curr : (Env, U32, U32)
= (env, 1, last)
-- Each step we show the appropriate text folloed by a newline and
-- then increment the value.
and step : IterStep (Env, U32, U32)
= \(env, n, last) =>
let env = if
| (n % 3 == 0) && (n % 5 == 0) -> show_string (env, "FizzBuzz")
| (n % 3 == 0) -> show_string (env, "Fizz")
| (n % 5 == 0) -> show_string (env, "Buzz")
| else -> show_u32 (env, n)
and env = newline env
in (env, n + 1, last)
-- We continue while we have a value less that the final value.
and condition : IterCondition (Env, U32, U32)
= \(env, n, last) =>
if n <= last then Continue else Stop
-- Build and return the iterator
in iterator (curr, step, condition)
-- An iterator over the fibbonaci sequence
type Fib = #{ p1 : U32, p2 : U32 }
fib : Env -> Iterator (Env, Fib)
fib env =
-- We track the current environment and the last two values in the
-- sequence. The -1st value is 0 and the 0th value is 1.
let curr : (Env, Fib)
= (env, #{ p1 = 1, p2 = 0 })
-- Each step we show the current value.
-- The n-1th value becomes the current value and then the current
-- value becomes the sum of the previous two.
and step : IterStep (Env, Fib)
= \(env, #{ p1, p2 }) =>
let env = show_u32 (env, p1)
and env = newline env
and n = p1 + p2
in (env, #{ p1 = n, p2 = p1 })
-- We stop when the current value would be greater than 1000.
and complete : IterCondition (Env, Fib)
= \(_, fib) =>
if fib.p1 < 1000 then Continue else Stop
in iterator (curr, step, complete)
-- This is the main program.
prog : Env -> Env
prog env =
-- First we perform fizzbuzz for all values up to 30.
let env = newline (show_string (env, "FizzBuzz:"))
and (env, _, _) = iterate (fizzbuzz (env, 30))
and env = newline env
-- The we run the fibonacci iterator.
and env = newline (show_string (env, "Fibonacci sequence:"))
and (env, _) = iterate (fib env)
and env = newline env
-- And now we are done.
in show_string (env, "Done!\n")