packages feed

alms-0.4.9: examples/ex26-let-bang-array.alms

(* An encoding of Wadler's let! construct.
   Allows temporarily viewing an array as unlimited/read-only. *)

#load "libarraycap"

open AArray

abstype ('t, 'c) ureadcap_rep qualifier A
  = Available of ('t, 'c) readcap
  | CheckedOut
  | Defunct
with
  abstype ('t, 'c) ureadcap qualifier U
    = MkCap of ('t, 'c) ureadcap_rep ref
  with

    (* We represent this thing with (essentially) as a spinlock.
       Acquire the spinlock: *)
    let acquireBang['t, 'c] (r: ('t, 'c) ureadcap_rep ref) =
      let rec loop (): ('t, 'c) readcap =
        match r <- CheckedOut with
        | Available c -> c
        | CheckedOut  -> loop ()
        | Defunct     -> failwith "letBang: attempt to use defunct ureadcap"
      in loop ()

    (* Given a capability, create a temporary, unlimited read capability
       and pass that to a call-back.  Return the result of the callback
       and the restored capability. *)
    let letBang['t, 'c, `a] (c: ('t, 'c) readcap)|
                                (k: ('t, 'c) ureadcap -o `a)
                                : `a * ('t, 'c) readcap =
      let r  = ref (Available c) in
      let uc = MkCap r in
      let a  = k uc in
      let c  = acquireBang r in
        r <- Defunct;
        (a, c)

    let applyBang['t,'c,`r]
             (k: ('t, 'c) readcap -o `r * ('t, 'c) readcap)
             |
             (MkCap r: ('t, 'c) ureadcap)
             : `r =
      let (result, c) = k (acquireBang r) in
        r <- Available c;
        result

    let liftBang['t,'c,`r]
             (k: ('t, 'c) readcap -> `r * ('t, 'c) readcap)
             (MkCap r: ('t, 'c) ureadcap)
             : `r =
      let (result, c) = k (acquireBang r) in
        r <- Available c;
        result

    let getAU['a,'t,'c] (a: ('a, 't) array) (ix: int) =
      liftBang (get['a,'t,'c] a ix)

    let putAU['a,'t] (a: ('a, 't) array) (ix: int) (new: 'a) =
      let f (cap: 't writecap) = ((), set['a,'t] a ix new cap) in
        liftBang f
  end
end

type 't uwritecap = ('t, 1) ureadcap

let test () =
  let n = 10 in
  let Pack('t, a, cap) = new[int] n 0 in
    let rec loop (i: int) (cap: 't writecap): 't writecap =
      if i >= n
        then cap
        else loop (i + 1) (set a i (i * i) cap) in
    let cap = loop 0 cap in
    let (r, cap) = letBang cap
      (fun (cap: 't uwritecap) ->
         getAU a 1 cap + getAU a 3 cap + getAU a 5 cap) in
      set a 0 (-1) cap;
      r

in print (test ())