packages feed

alms-0.5.0: lib/libbasis.alms

module INTERNALS = struct
  module Exn = struct
    open Prim.Exn

    exception Failure of string
    exception IOError of string 
    exception Blame of string * string
    exception PatternMatch of string * string list
    exception UninitializedLetRec of string

    let failwith (msg: string) =
      raise (Failure msg)

    let tryfun[`a] (thunk: unit -o `a) : exn + `a =
      match tryfun_string thunk with
      | Right a        -> Right[exn,`a] a
      | Left (Left e)  -> Left[exn,`a] e
      | Left (Right s) -> Left[exn,`a] (IOError s)

    let raiseBlame (who: string) (what: string) =
      raise (Blame (who, what))
  end

  local
    module INTERNALS = struct
      module Exn = Exn
    end
  with
    module Contract = struct
      type party = string
      type (`a, `b) coercion = party * party -> `a -> `b
      type `a contract = party * party -> `a -> `a

      (* Flat contracts for unlimited values. *)
      let flat['a] (pred: 'a -> bool) : 'a contract =
        fun (neg: party, pos: party) (a: 'a) ->
          if pred a
            then a
            else Exn.raiseBlame pos "violated contract"

      (* Flat contracts for affine values. *)
      let flatA[`a] (pred: `a -> bool * `a) : `a contract =
        fun (neg: party, pos: party) (a: `a) ->
          match pred a with
          | (true, a)  -> a
          | (false, _) -> Exn.raiseBlame pos "violated contract"

      (* The identity contract. *)
      let any[`a] : `a contract =
        fun (_: party, _: party) (a: `a) -> a

      (* Add domain and codomain contracts to a function. *)
      let func[`q]
              [`a1, `a2] (dom: (`a1, `a2) coercion)
              [`b1, `b2] (cod: (`b1, `b2) coercion)
              : (`a2 -[`q]> `b1, `a1 -[`q]> `b2) coercion =
        fun (neg: party, pos: party) (f: `a2 -[`q]> `b1) ->
          fun (a: `a1) -> cod (neg, pos) (f (dom (pos, neg) a))

      (* Coerce an affine function to an unlimited function, and
         check dynamically that it's applied only once. *)
      let affunc[`a1, `a2] (dom: (`a1, `a2) coercion)
                [`b1, `b2] (cod: (`b1, `b2) coercion)
                : (`a2 -o `b1, `a1 -> `b2) coercion =
        fun (neg: party, pos: party) (f: `a2 -o `b1) ->
          let rf = ref (Some f) in
            fun (a: `a1) ->
              match rf <- None[`a2 -o `b1] with
              | Some f -> cod (neg, pos) (f (dom (pos, neg) a))
              | None   -> Exn.raiseBlame neg "reused one-shot function"

      (* Check that an ostensibly unlimited function is actually
         unlimited. *)
      let unfunc[`a1, `a2] (dom: (`a1, `a2) coercion)
                [`b1, `b2] (cod: (`b1, `b2) coercion)
                : (`a2 -> `b1, `a1 -> `b2) coercion =
        fun (neg: party, pos: party) (f: `a2 -> `b1) ->
          fun (x: `a1) ->
            let x' = dom (pos, neg) x in
            let y  = try f x' with
                     | Exn.Blame(p, "reused one-shot function")
                         -> Exn.raiseBlame pos "raised blame" in 
            cod (neg, pos) y
    end
  end
end

let not (b: bool) = if b then false else true
let (!=)['a] (x: 'a) (y: 'a) = not (x == y)

let flip['a,'b,'c] (f: 'a -> 'b -> 'c) (y: 'b) (x: 'a) = f x y

let (<) (x: int) (y: int) = not (y <= x)
let (>) = flip (<)
let (>=) = flip (<=)
let (>.) = flip (<.)
let (>=.) = flip (<=.)

type `a × `b = `a * `b
(* These have too-tight precedences *)
let (≠)  = (!=)
let (≤)  = (<=)
let (≥)  = (>=)
let (≤.) = (<=.)
let (≥.) = (>=.)

let null = fun 'a (x : 'a list) ->
  match x with
  | Nil -> true
  | _   -> false
let anull = fun `a (xs : `a list) ->
  match xs with
  | Nil          -> (Nil[`a], true)
  | Cons(x, xs') -> (Cons(x, xs'), false)
let hd = fun 'a (xs : 'a list) ->
  let Cons(x, _) = xs in x
let tl = fun 'a (xs : 'a list) ->
  let Cons(_, xs') = xs in xs'
let foldr =
  let rec foldr `a `b (f : `a -> `b -o `b)
                        (z : `b) |[b](xs : `a list) : `b =
        match xs with
        | Nil -> z
        | Cons(x,xs) -> f x (foldr f z xs)
   in foldr
let foldl =
  let rec foldl `a `b (f : `a -> `b -o `b)
                        (z : `b) |[b](xs : `a list) : `b =
        match xs with
        | Nil -> z
        | Cons(x,xs) -> foldl f (f x z) xs
   in foldl
let map `a `b (f: `a -> `b) (xs: `a list) =
      foldr (fun (x: `a) (xs': `b list) -> Cons (f x, xs')) Nil xs
let filter 'a (f: 'a -> bool) (xs: 'a list) =
      foldr (fun (x: 'a) (xs': 'a list) ->
               if f x then Cons(x, xs') else xs')
            Nil
let mapFilterA `a `b (f: `a -> `b option) (xs: `a list) =
      foldr (fun (x: `a) (xs': `b list) ->
               match f x with
               | Some y -> Cons(y, xs')
               | None   -> xs')
            Nil
            xs
let revApp[`c] (xs : `c list) (ys : `c list) =
  let cons (x : `c) (acc : `c list) = Cons (x, acc) in
    foldl cons ys xs
let rev[`b] (xs : `b list) = revApp xs Nil
let append[`a] (xs : `a list) = revApp (rev xs)
let length[`a] (xs : `a list) =
  foldr (fun (x : `a) -> (+) 1) 0 xs
let lengthA[`a] (xs : `a list) =
  let count (x : `a) (n : int, xs' : `a list) =
       (1 + n, Cons (x, xs')) in
    foldr count (0, Nil[`a]) xs

let fst[`a,`b] (x: `a, _: `b) = x
let snd[`a,`b] (_: `a, y: `b) = y

let (=>!) [`a] (x: `a) [`b] (y: `b) = (y, x)
let (⇒) = (=>!)

let (←) = (<-)
let (⇐) = (<-!)

open INTERNALS
open Exn