package grenier
A collection of various algorithms in OCaml
Install
Dune Dependency
Authors
Maintainers
Sources
grenier-0.15.tbz
sha256=dec7f84b9e93d5825f10c7dea84d5a74d7365ede45664ae63c26b5e8045c1c44
sha512=b8aa1569c2e24b89674d1b34de34cd1798896bb6a53aa5a1287f68cee880125e6b687f66ad73da9069a01cc3ece1f0684f48328b099d43529bff736b772c8fd8
doc/src/grenier.binder_introducer/binder_introducer.ml.html
Source file binder_introducer.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 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
(* * Copyright (c) 2022 Frédéric Bour <frederic.bour@lakaban.net> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. *) (* Generic code to reveal sharing in a cyclic graph *) type 'a graph = 'a Fastdom.graph = { memoize: 'b. ('a -> 'b) -> ('a -> 'b); successors: 'b. ('b -> 'a -> 'b) -> 'b -> 'a -> 'b; } type ('term, 'var) binding_structure = { (* Rewrite subterms of a term with a custom function *) map_subterms: ('term -> 'term) -> 'term -> 'term; (* Produce a fresh variable for a term *) name_term: 'term -> 'var; (* Injection from variable to terms *) var_term: 'var -> 'term; (* [introduce_let ~recursive bindings body] create a possibly recursive let-binder term that binds the names in [bindings] in the scope of [body] *) introduce_let: recursive:bool -> ('var * 'term) list -> 'term -> 'term; } type occurrence = { mutable min_scope: int; cursor: int ref; } let explicit_sharing (type a b) (gr : a Fastdom.graph) (bs : (a, b) binding_structure) t = let postorder, dominance = Fastdom.dominance gr t in let count = Array.length postorder in let bindings = Array.make count [] in let var_name = Array.make count None in let tag = match Fastdom.predecessors tag with | [] -> false | [_] -> Fastdom.node tag == t | _ :: _ :: _ -> true in for i = count - 1 downto 0 do let tag = postorder.(i) in if share tag then begin let node = Fastdom.node tag in let var = bs.name_term node in var_name.(i) <- Some (bs.var_term var); let dominator = Fastdom.dominator tag in let index = Fastdom.postorder_index dominator in bindings.(index) <- (var, tag) :: bindings.(index) end done; let null_occurrence = {min_scope = 0; cursor = ref 0} in let rec_occurrences = Array.make count null_occurrence in let rec traverse ~is_binding t = let cursor = ref max_int in let bindings, t = let tag = dominance t in let id = Fastdom.postorder_index tag in if id = -1 then ([], t) else match var_name.(id) with | Some name when not is_binding -> let occ = rec_occurrences.(id) in if !(occ.cursor) < occ.min_scope then occ.min_scope <- !(occ.cursor); ([], name) | _ -> match bindings.(id) with | [] -> ([], t) | bindings' -> bindings.(id) <- []; let init_occurrence (_, tag) = rec_occurrences.(Fastdom.postorder_index tag) <- { min_scope = max_int; cursor; } in List.iter init_occurrence bindings'; (bindings', t) in let t = bs.map_subterms traverse_child t in match List.mapi traverse_binding bindings with | [] -> t | bindings -> let normalize_scope (_, occ, _) min_scope = if min_scope < occ.min_scope then ( occ.min_scope <- min_scope; min_scope ) else occ.min_scope in ignore (List.fold_right normalize_scope bindings max_int : int); let let_ ~recursive group body = match group with | [] -> body | bindings -> bs.introduce_let ~recursive (if recursive then bindings else List.rev bindings) body in let rec nonrec_bindings group ~scope_limit ~index = function | [] -> let_ ~recursive:false group t | (var, occ, t') :: bindings when occ.min_scope > index -> if index >= scope_limit then ( let_ ~recursive:false group (nonrec_bindings [var, t'] ~scope_limit:occ.min_scope ~index:(index + 1) bindings) ) else nonrec_bindings ((var, t') :: group) ~scope_limit:(min occ.min_scope scope_limit) ~index:(index + 1) bindings | bindings -> let_ ~recursive:false group (rec_bindings [] index bindings) and rec_bindings group index = function | (var, occ, t') :: bindings when occ.min_scope <= index -> rec_bindings ((var, t') :: group) (index + 1) bindings | bindings -> let_ ~recursive:true group (nonrec_bindings [] ~scope_limit:max_int ~index bindings) in nonrec_bindings [] ~scope_limit:max_int ~index:0 bindings and traverse_child t = traverse ~is_binding:false t and traverse_binding index (var, tag) = let occ = rec_occurrences.(Fastdom.postorder_index tag) in occ.cursor := index; (var, occ, traverse ~is_binding:true (Fastdom.node tag)) in traverse ~is_binding:true t
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>