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