packages feed

alms-0.6.5: lib/libbasis.alms

module INTERNALS = struct
  module PrimTypes = INTERNALS.PrimTypes

  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 (thunk: unit -o `a) : exn + `a =
      match tryfun_string thunk with
      | Right a        -> Right a
      | Left (Left e)  -> Left e
      | Left (Right s) -> Left (IOError s)

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

  local
    module INTERNALS = struct
      module Exn       = Exn
      module PrimTypes = PrimTypes
    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 (pred: 'a -> bool) : 'a contract =
        λ (neg: party, pos: party) (a: 'a) ->
          if pred a
            then a
            else Exn.raiseBlame pos "violated contract"

      (* Flat contracts for affine values. *)
      let flatA (pred: `a -> bool * `a) : `a contract =
        λ (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 contract =
        λ (_: party, _: party) (a: `a) -> a

      (* Add domain and codomain contracts to a function. *)
      let func
               (dom: (`a1, `a2) coercion)
               (cod: (`b1, `b2) coercion)
              : (`a2 -[`q]> `b1, `a1 -[`q]> `b2) coercion =
        λ (neg: party, pos: party) (f: `a2 -[`q]> `b1) ->
          λ (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 (dom: (`a1, `a2) coercion)
                 (cod: (`b1, `b2) coercion)
                : (`a2 -o `b1, `a1 -> `b2) coercion =
        λ (neg: party, pos: party) (f: `a2 -o `b1) ->
          let rf = ref (Some f) in
            λ (a: `a1) ->
              match rf <- None 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 (dom: (`a1, `a2) coercion)
                 (cod: (`b1, `b2) coercion)
                : (`a2 -> `b1, `a1 -> `b2) coercion =
        λ (neg: party, pos: party) (f: `a2 -> `b1) ->
          λ (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

module Function = struct
  let id x             = x
  let const _ x        = x
  let flip f y x       = f x y
  let curry f x y      = f (x, y)
  let uncurry f (x, y) = f x y
  let compose f g x    = f (g x)
  let ($) f x          = f x

  (* Useful for implicit threading syntax: *)
  let ($>) f x         = ((), f x)
  let ($<) f x         = (f x, ())
end

open Function

module Bool = struct
  let not (b: bool) = if b then false else true
  let (!=) (x: 'a) (y: 'a) = not (x == y)
end

open Bool

module Int = struct
  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 (≥.) = (>=.)
end

open Int

module List = struct
  let null x =
    match x with
    | [] -> true
    | _  -> false

  let anull xs =
    match xs with
    | []       -> ([], true)
    | x :: xs' -> (x :: xs', false)

  let hd (x :: _) = x

  let tl (_ :: xs) = xs

  let rec foldr f z xs =
    match xs with
    | []      -> z
    | x :: xs -> f x (foldr f z xs)

  let rec foldl f z xs =
    match xs with
    | []      -> z
    | x :: xs -> foldl f (f x z) xs

  let map f = foldr (λ x xs' -> f x :: xs') []

  let filter f xs = foldr (λ x xs' -> if f x then x :: xs' else xs') []

  let mapFilterA f =
        foldr (λ x xs' ->
                 match f x with
                 | Some y -> y :: xs'
                 | None   -> xs')
              []

  let revApp xs ys =
    let cons x acc = x :: acc in
      foldl cons ys xs

  let rev xs = revApp xs []

  let append xs = revApp (rev xs)

  let length = foldr (λ _ -> (+) 1) 0

  let lengthA xs =
    let count x (n, xs') = (1 + n, x :: xs') in
      foldr count (0, []) xs

  let rec openFoldr f z o xs = match xs with
    | #Nil         -> z
    | #Cons(x,xs') -> f x (openFoldr f z o xs')
    | other        -> o other
end

open List

let fst (x, _) = x
let snd (_, y) = y

let (=>!) x y = (y, x)
let (⇒) = (=>!)

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

type (|->)  = type Prim.Row.(|->)
let rowCase = Prim.Row.rowCase

module Exn      = INTERNALS.Exn
module Contract = INTERNALS.Contract
open Exn