module Common = struct let id a = a let dup a = a, a let some v = Some v let curry2 f a b = f (a, b) let uncurry2 f (a, b) = f a b let curry3 f = curry2 (curry2 f) let uncurry3 f = uncurry2 (uncurry2 f) let first a b = a let second a b = b let ( =* ) a b = try a = b with Invalid_argument _ -> a == b let ( <>* ) a b = try a <> b with Invalid_argument _ -> a != b end open Common (* TODO: add necessary functions to Event (such as value change -> event) so that we may rewrite FrCore without manipulating events directly *) module Event = struct type 'a t = 'a option let none = None let tag v = function | Some _ -> Some v | None -> None let attach v = function | Some a -> Some (v, a) | None -> None let map f = function | Some a -> Some (f a) | None -> None let may = function | Some a -> a | None -> None let lmerge a b = match a, b with | Some _, _ -> a | _, _ -> b let rmerge a b = match a, b with | _, Some _ -> b | _, _ -> a let merge f a b = match a, b with | Some a, Some b -> Some (f a b) | Some _, None -> a | None, Some _ -> b | None, None -> None let map_merge fa fb fab a b = match a, b with | Some a, Some b -> Some (fab a b) | Some a, None -> Some (fa a) | None, Some b -> Some (fb b) | None, None -> None let cat l = match (List.fold_left (fun r -> function | Some a -> a :: r | None -> r) [] l) with | [] -> None | r -> Some (List.rev r) let join a b = match a, b with | Some a, Some b -> Some (a, b) | _, _ -> None let split = function | Some (a, b) -> Some a, Some b | None -> None, None let filter f = function | Some a when f a -> Some a | _ -> None let map_filter f = function | Some a -> f a | None -> None let get e = function | Some _ -> Some e | None -> None (* internal *) let return a = Some a let map_default d f = function | Some a -> f a | None -> d let is_event = function Some _ -> true | None -> false let from_event = function Some a -> a | None -> assert false end type ('i, 'o) sf = | TF of ('i -> ('i, 'o) transition) | Const of 'o and ('i, 'o) transition = ('i, 'o) sf option * 'o exception Undefined_signal let transition sf i = match sf with | TF tf -> begin match tf i with | Some sf', o -> sf', o | None, o -> sf, o end | Const o -> sf, o let make_sf tf = TF tf let is_constant = function Const _ -> true | _ -> false (* Basic signals *) let constant a = Const a let arr f = make_sf (fun i -> None, f i) let arr2 f = arr (uncurry2 f) let rec (>>>) a b = make_sf (fun i -> let a', ao = transition a i in let b', o = transition b ao in match a', b' with | _, Const bo' -> Some (constant bo'), o | Const ao', _ -> Some (constant (snd (transition b' ao'))), o | _ -> Some (a' >>> b'), o) let (<<<) a b = b >>> a let rec first a = make_sf (fun (ai, bi) -> let a', ao = transition a ai in Some (first a'), (ao, bi)) let rec second b = make_sf (fun (ai, bi) -> let b', bo = transition b bi in Some (second b'), (ai, bo)) let rec ( *** ) a b = make_sf (fun (ai, bi) -> let a', ao = transition a ai and b', bo = transition b bi in match a', b' with | Const ao', Const bo' -> Some (constant (ao', bo')), (ao, bo) | _ -> Some (a' *** b'), (ao, bo)) let rec (&&&) a b = make_sf (fun i -> let a', ao = transition a i and b', bo = transition b i in match a', b' with | Const ao', Const bo' -> Some (constant (ao', bo')), (ao, bo) | _ -> Some (a' &&& b'), (ao, bo)) let returnA = TF (fun i -> None, i) (* I doubt this works at all *) (*let rec loop a = { tf = (fun ai -> let rec a'_ao_bo = lazy (transition a (ai, (lazy (snd (snd (Lazy.force a'_ao_bo)))))) in let a', (ao, bo) = Lazy.force a'_ao_bo in loop a', ao) }*) let rec loop init a = make_sf (fun ai -> let rec f bi = let a', (ao, bo) = transition a (ai, bi) in match a' with | Const (ao', bo') -> Some (constant ao'), ao | _ -> if bo =* bi then Some (loop bo a'), ao else f bi in f init) let rec loopq init a = make_sf (fun ai -> let rec f bi = let a', (ao, bo) = transition a (ai, bi) in match a' with | Const (ao', bo') -> Some (constant ao'), ao | _ -> if bo == bi then Some (loop bo a'), ao else f bi in f init) let fix g f = let sf' = ref (make_sf (fun _ -> raise Undefined_signal)) in let sf = make_sf (fun i -> let sf, o = transition !sf' i in Some sf, o) in let r = f sf in sf' := g r; r let identity = returnA (* Event signals *) let never = Const None let now v = make_sf (fun _ -> Some never, Some v) let edge v = let rec sf = function | true -> make_sf (fun i -> Some (sf i), None) | false -> make_sf (fun i -> Some (sf i), if i then Some v else None) in sf true let delta f = let rec sf init = make_sf (fun i -> if i != init then Some (sf i), Some (f init i) else None, None) in make_sf (fun i -> Some (sf i), None) let changes = let rec sf init = make_sf (fun i -> if i <>* init then Some (sf i), Some i else None, None) in TF (fun i -> Some (sf i), None) let changesq = let rec sf init = make_sf (fun i -> if i != init then Some (sf i), Some i else None, None) in TF (fun i -> Some (sf i), None) let latch = let rec sf init = make_sf (function | i, Some _ -> Some (sf i), Some init | i, None -> Some (sf i), None) in TF (function | i, Some _ -> Some (sf i), Some i | i, None -> Some (sf i), None) let once = TF (function | Some i -> Some never, Some i | None -> None, None) let rec take = function | 0 -> never | n -> make_sf (function | Some i -> Some (take (n - 1)), Some i | None -> None, None) let rec drop = function | 0 -> identity | n -> make_sf (function | Some i -> Some (drop (n - 1)), None | None -> None, None) (* Parallel signals *) let rec par l = make_sf (fun i -> let l', o = List.split (List.map (fun sf -> transition sf i) l) in if List.for_all is_constant l' then let o' = List.rev (List.fold_left (fun o' -> function | Const ao' -> ao' :: o' | _ -> assert false) [] l') in Some (constant o'), o else Some (par l'), o) (* Behavior signals *) let rec hold init = make_sf (function Some i -> Some (hold i), i | None -> None, init) let track = hold let gate = let rec sf init = make_sf (function | i, Some _ -> Some (sf i), i | _, None -> None, init) in TF (function i, _ -> Some (sf i), i) (* Accumulators *) let rec accum init = make_sf (function | Some f -> let o = f init in Some (accum o), Some o | None -> None, None) let rec collect f init = make_sf (function | Some i -> let o = f init i in Some (collect f o), Some o | None -> None, None) (* Switchers *) let rec switch sf c = make_sf (fun i -> match transition c i with | c', None -> let sf', o = transition sf i in if is_constant c' then Some sf', o else Some (switch sf' c'), o | c', Some sf -> let sf', o = transition sf i in if is_constant c' then Some sf', o else Some (switch sf' c'), o) (*let rswitch sf = switch (arr fst >>> sf) (arr (fun (i, c) -> Event.map (fun sf -> arr fst >>> sf) c))*) let rec rswitch sf = make_sf (function | i, None -> let sf', o = transition sf i in Some (rswitch sf'), o | i, Some sf -> let sf', o = transition sf i in Some (rswitch sf'), o) (*let switch sf c = (identity &&& c) >>> rswitch sf*) let rec dswitch (sf: ('a, 'b Event.t) sf) c = make_sf (fun i -> match transition c i with | c', None -> let sf', o = transition sf i in if is_constant c' then Some sf', o else Some (dswitch sf' c'), o | c', Some dsf -> let _, o = transition sf i (* we must transition the new signal function in order to preserve the property of event conservation *) and sf', _ = transition dsf i in if is_constant c' then Some sf', o else Some (dswitch sf' c'), o) let rec drswitch (sf: ('a, 'b Event.t) sf) = make_sf (function | i, None -> let sf', o = transition sf i in Some (drswitch sf'), o | i, Some dsf -> let _, o = transition sf i (* we must transition the new signal function in order to preserve the property of event conservation *) and sf', _ = transition dsf i in Some (drswitch sf'), o) let rec srswitch g f init = let rec srswitch_r sf o = make_sf (function | i, None -> let sf', o' = transition sf i in Some (srswitch_r sf' o'), o' | i, Some f -> let sf', o' = transition (f (g o)) i in Some (srswitch_r sf' o'), o') in make_sf (function | i, None -> let sf', o' = transition (f init) i in Some (srswitch_r sf' o'), o' | i, Some f -> let sf', o' = transition (f init) i in Some (srswitch_r sf' o'), o') let rec rcollapse = let rec rcollapse_r cur sf = make_sf (function | i, cur' when cur' == cur -> let sf', o' = transition sf i in Some (rcollapse_r cur' sf'), o' | i, cur' -> let sf', o' = transition cur' i in Some (rcollapse_r cur' sf'), o') in TF (fun (i, cur') -> let sf', o' = transition cur' i in Some (rcollapse_r cur' sf'), o') let collapse c = (identity &&& c) >>> rcollapse let rec srcollapse g init = let rec srcollapse_r f sf o = make_sf (function | i, f' when f' == f -> let sf', o' = transition sf i in Some (srcollapse_r f' sf' o'), o' | i, f' -> let sf', o' = transition (f' (g o)) i in Some (srcollapse_r f' sf' o'), o') in make_sf (fun (i, f') -> let sf', o' = transition (f' init) i in Some (srcollapse_r f' sf' o'), o') let rec acollapse map = make_sf (fun (i, s) -> let v', o = transition (List.assoc s map) i in Some (acollapse (List.map (fun (k, v) -> k, if k = s then v' else fst (transition v i)) map)), o) let const_arr f = make_sf (fun i -> let stop, o = f i in if stop then Some (constant o), o else None, o) let reactimate sf i = transition sf i