packages feed

swarm-0.6.0.0: example/rectypes.sw

// 'rec t. F(t)' creates a recursive type which is the solution of t = F(t).
// For example 'rec l. Unit + Int * l' is the type l such that l = Unit + Int * l,
// that is, arbitrary-length finite lists of Int.
//
// Recursive types are equal up to alpha-renaming, so e.g.
// (rec l. Unit + Int * l) = (rec q. Unit + Int * q)

////////////////////////////////////////////////////////////
// Lists
////////////////////////////////////////////////////////////

tydef List a = rec l. Unit + a * l end

def nil : List a = inl () end
def cons : a -> List a -> List a = \x. \l. inr (x, l) end

def foldr : (a -> b -> b) -> b -> List a -> b = \f. \z. \xs.
  case xs
    (\_. z)
    (\c. f (fst c) (foldr f z (snd c)))
end

def map : (a -> b) -> List a -> List b = \f.
  foldr (\y. cons (f y)) nil
end

def append : List a -> List a -> List a = \xs. \ys.
  foldr cons ys xs
end

def concat : List (List a) -> List a = foldr append nil end

def sum : List Int -> Int =
  foldr (\x. \y. x + y) 0
end

def twentySeven = sum (cons 12 (cons 5 (cons 3 (cons 7 nil)))) end

// Note that if a function returns e.g. (rec t. Unit + (Int * Int) * t),
// that is the *same type* as List (Int * Int), so we can use any List
// functions on the output.

def someFun : Int -> (rec t. Unit + (Int * Int) * t) = \x. inr ((x, x), inl ()) end

def doSomethingWithSomeFun : List (Int * Int) =
  (cons (2,3) (cons (4,7) (someFun 5)))
end

////////////////////////////////////////////////////////////
// Binary trees with a at internal nodes and b at leaves
////////////////////////////////////////////////////////////

tydef BTree a b = rec bt. b + bt * a * bt end

def leaf : b -> BTree a b = inl end

def branch : BTree a b -> a -> BTree a b -> BTree a b =
  \l. \a. \r. inr (l, a, r)
end

def foldBTree : (b -> c) -> (c -> a -> c -> c) -> BTree a b -> c =
  \lf. \br. \t.
    case t
      lf
      // fst p, fst (snd p), snd (snd p) is annoying; see #1893
      (\p. br (foldBTree lf br (fst p)) (fst (snd p)) (foldBTree lf br (snd (snd p))))
end

def max : Int -> Int -> Int = \a. \b. if (a > b) {a} {b} end

def height : BTree a b -> Int =
  foldBTree (\_. 0) (\l. \_. \r. 1 + max l r)
end

////////////////////////////////////////////////////////////
// Rose trees
////////////////////////////////////////////////////////////

// It would be better to reuse the definition of List
// and define Rose a = rec r. a * List r,
// but we do it this way just to show off nested rec
tydef Rose a = rec r. a * (rec l. Unit + r * l) end

def foldRose : (a -> List b -> b) -> Rose a -> b = \f. \r.
  f (fst r) (map (foldRose f) (snd r))
end

def flatten : Rose a -> List a =
  foldRose (\a. \ts. cons a (concat ts))
end

////////////////////////////////////////////////////////////
// Equirecursive types
////////////////////////////////////////////////////////////

// Swarm has equirecursive types, which means a recursive type is
// *equal to* its unfolding.  This has some interesting consequences
// including the fact that types are equal if their infinite unfoldings
// would be equal.

// For example, U1 and U2 below are the same, and the Swarm
// typechecker can tell:

tydef U1 = rec u1. Unit + u1 end
tydef U2 = rec u2. Unit + Unit + u2 end

def u : U1 -> U2 = \u. u end