Alpha equivalence checker for arbitrary lambda terms
7

Configure Feed

Select the types of activity you want to include in your feed.

ego / ocaml / lib / debruijn.ml
4.3 kB 160 lines
1type t = 2 | Var of int 3 | Free of string 4 | Lam of t 5 | App of t * t 6 7module SSet = Set.Make (String) 8 9exception Unbound_index of int 10 11let rec free_variables = function 12 | Var _ -> SSet.empty 13 | Free x -> SSet.singleton x 14 | Lam b -> free_variables b 15 | App (f, a) -> SSet.union (free_variables f) (free_variables a) 16 17let free_variable_list t = SSet.elements (free_variables t) 18 19let rec pretty = function 20 | Var i -> "#" ^ string_of_int i 21 | Free x -> x 22 | Lam b -> "\\. " ^ pretty b 23 | App (f, a) -> 24 let pf = 25 match f with Var _ | Free _ | App _ -> pretty f | _ -> "(" ^ pretty f ^ ")" 26 in 27 let pa = 28 match a with Var _ | Free _ -> pretty a | _ -> "(" ^ pretty a ^ ")" 29 in 30 pf ^ " " ^ pa 31 32let rec shift cutoff amount t = 33 match t with 34 | Var i -> if i >= cutoff then Var (i + amount) else Var i 35 | Free x -> Free x 36 | Lam b -> Lam (shift (cutoff + 1) amount b) 37 | App (f, a) -> App (shift cutoff amount f, shift cutoff amount a) 38 39let rec subst j s = function 40 | Var i -> 41 if i = j then s else if i > j then Var (i - 1) else Var i 42 | Free x -> Free x 43 | Lam b -> Lam (subst (j + 1) (shift 0 1 s) b) 44 | App (f, a) -> App (subst j s f, subst j s a) 45 46let substitute j s body = subst j s body 47 48let rec convert_from_named_depth env = function 49 | Named.Var x -> begin 50 match List.assoc_opt x env with 51 | Some i -> Var i 52 | None -> Free x 53 end 54 | Named.Lam (x, b) -> Lam (convert_from_named_depth ((x, 0) :: List.map (fun (v, i) -> (v, i + 1)) env) b) 55 | Named.App (f, a) -> 56 App (convert_from_named_depth env f, convert_from_named_depth env a) 57 | Named.Subst (x, s, b) -> 58 let body = Named.substitute x s b in 59 convert_from_named_depth env body 60 61let convert_from_named t = convert_from_named_depth [] t 62 63let convert_to_named t = 64 let fv = free_variables t in 65 let fresh_avoid avoid base = 66 if not (List.mem base avoid) then base 67 else 68 let rec go i = 69 let cand = base ^ string_of_int i in 70 if List.mem cand avoid then go (i + 1) else cand 71 in 72 go 0 73 in 74 let rec go env = function 75 | Var i -> begin 76 match List.nth_opt env i with 77 | Some x -> Named.Var x 78 | None -> raise (Unbound_index i) 79 end 80 | Free x -> Named.Var x 81 | Lam b -> 82 let avoid = SSet.elements fv @ env in 83 let x = fresh_avoid avoid "v" in 84 Named.Lam (x, go (x :: env) b) 85 | App (f, a) -> Named.App (go env f, go env a) 86 in 87 go [] t 88 89let is_value = function Lam _ -> true | _ -> false 90 91let rec step = function 92 | App (Lam b, a) -> Some (subst 0 a b) 93 | App (f, a) when not (is_value f) -> begin 94 match step f with 95 | Some f' -> Some (App (f', a)) 96 | None -> begin 97 match step a with Some a' -> Some (App (f, a')) | None -> None 98 end 99 end 100 | App (f, a) -> begin 101 match step a with Some a' -> Some (App (f, a')) | None -> None 102 end 103 | Lam b -> begin 104 match step b with Some b' -> Some (Lam b') | None -> None 105 end 106 | _ -> None 107 108let step_limit = 10000 109 110let normalise t = 111 let rec go n t = 112 if n >= step_limit then t 113 else match step t with Some t' -> go (n + 1) t' | None -> t 114 in 115 go 0 t 116 117let normalise_counted t = 118 let count = ref 0 in 119 let maxd = ref 0 in 120 let rec walk d t = 121 incr count; 122 if d > !maxd then maxd := d; 123 match t with 124 | Var _ | Free _ -> () 125 | Lam b -> walk (d + 1) b 126 | App (f, a) -> walk (d + 1) f; walk (d + 1) a 127 in 128 walk 0 t; 129 let rec go n t = 130 if n >= step_limit then t 131 else 132 match step t with 133 | Some t' -> walk 0 t'; go (n + 1) t' 134 | None -> t 135 in 136 (go 0 t, !count, !maxd) 137 138let alpha_equivalent t1 t2 = normalise t1 = normalise t2 139 140let rec well_scoped depth = function 141 | Var i -> i < depth 142 | Free _ -> true 143 | Lam b -> well_scoped (depth + 1) b 144 | App (f, a) -> well_scoped depth f && well_scoped depth a 145 146let alpha_equivalent_counted t1 t2 = 147 let count = ref 0 in 148 let maxd = ref 0 in 149 let rec go d a b = 150 incr count; 151 if d > !maxd then maxd := d; 152 match (a, b) with 153 | Var i, Var j -> i = j 154 | Free x, Free y -> x = y 155 | Lam b1, Lam b2 -> go (d + 1) b1 b2 156 | App (f1, a1), App (f2, a2) -> go (d + 1) f1 f2 && go (d + 1) a1 a2 157 | _ -> false 158 in 159 let r = go 0 (normalise t1) (normalise t2) in 160 (r, !count, !maxd)