package brr
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>
Browser programming toolkit for OCaml
Install
dune-project
Dependency
Authors
Maintainers
Sources
brr-0.0.8.tbz
sha512=49e7bfbad2ea6a0139354e4a33c59c8a113c4c1e20a4f629bc5cad24aa801e474b4af10ce35adbda5d23dd294d1de5efa5b10bb3030d03f4758459977250a0f6
doc/src/brr/fut.ml.html
Source file fut.ml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106(*--------------------------------------------------------------------------- Copyright (c) 2020 The brr programmers. All rights reserved. SPDX-License-Identifier: ISC ---------------------------------------------------------------------------*) (* We represent futures by an object { fut : <promise> } with a single [fut] JavaScript Promise object which, by construction, *never* rejects. The promise is wrapped in an object because JavaScript's [resolve] which should be monadic [return] unfortunately also monadically [join]s. This JavaScript expression: Promise.resolve (Promise.resolve ("Noooooo!")) evaluates to: Promise {<fulfilled>: "Noooooo!"} instead of: Promise {<fulfilled>: Promise {<fulfilled>: ""Noooooo!""}} This makes it impossible to type [resolve] correctly in OCaml since it would need to have these two types: val resolve : 'a -> 'a Promise.t val resolve : 'a Promise.t -> 'a Promise.t In general this breaks type safety for example [bind]ing a ['a Fut.t Fut.t] value your function could end up with a ground value of type ['a] not the expected ['a Fut.t] value as argument. By wrapping the promise in an object we can control that. *) type 'a t = Jv.t (* a JavaScript object of the form: { fut : <promise> } *) let fut p = Jv.obj [| "fut", p |] let promise f = Jv.get f "fut" let promise' f = Jv.get f "fut" let create () = (* Ugly as shit but that's what new Promise gives us. *) let not_set = fun _ -> assert false in let is_set = fun _ -> Jv.throw (Jstr.v "The future is already set") in let setter = ref not_set in let set_setter resolve _reject = setter := resolve in let p = Jv.Promise.create set_setter in let set v = !setter v; setter := is_set in fut p, set let await f k = Jv.Promise.await (promise f) k let return v = fut @@ Jv.Promise.resolve v let bind f fn = fut @@ Jv.Promise.bind (promise f) (fun v -> promise (fn v)) let map fn f = bind f (fun v -> return (fn v)) let pair f0 f1 = fut @@ Jv.Promise.bind (promise f0) @@ fun v0 -> Jv.Promise.bind (promise f1) @@ fun v1 -> Jv.Promise.resolve (v0, v1) let of_list fs = let arr = Jv.of_list promise' fs in let all = Jv.Promise.all arr in let to_list l = Jv.Promise.resolve (Jv.to_list Obj.magic l) in fut @@ Jv.Promise.bind all to_list let tick ~ms = fut @@ Jv.Promise.create @@ fun res _rej -> ignore (Jv.apply (Jv.get Jv.global "setTimeout") Jv.[| callback ~arity:1 res; of_int ms |]) (* Converting with JavaScript promises *) type nonrec ('a, 'b) result = ('a, 'b) result t type 'a or_error = ('a, Jv.Error.t) result let ok v = return (Ok v) let error e = return (Error e) let of_promise' ~ok ~error p = let ok v = Jv.Promise.resolve (Ok (ok v)) in let error e = Jv.Promise.resolve (Error (error e)) in fut @@ Jv.Promise.then' p ok error let to_promise' ~ok ~error f = Jv.Promise.create @@ fun res rej -> await f @@ function | Ok v -> res (ok v) | Error e -> rej (error e) let of_promise ~ok v = of_promise' ~ok ~error:Jv.to_error v let to_promise ~ok v = to_promise' ~ok ~error:Jv.of_error v (* Future syntaxes *) module Syntax = struct let ( let* ) = bind let ( and* ) = pair let ( let+ ) f fn = map fn f let ( and+ ) = ( and* ) end module Result_syntax = struct let result_pair r = match r with | (Error _ as r), _ | _, (Error _ as r) -> r | Ok v0, Ok v1 -> Ok (v0, v1) let ( let* ) f fn = bind f @@ function | Ok v -> fn v | Error _ as e -> return e let ( and* ) f0 f1 = map result_pair (pair f0 f1) let ( let+ ) f fn = map (Result.map fn) f let ( and+ ) = ( and* ) end
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>