Last active
December 7, 2024 20:58
-
-
Save rntz/bf9622bc16aa20705a517529b7075ad0 to your computer and use it in GitHub Desktop.
Eager, lazy, & small-step "correct" fixed points
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
type var = string | |
type term = Var of var | |
| Lam of var * term | |
| App of term * term | |
| Fix of var * term (* only used for functions *) | |
| Lit of int | |
type value = Int of int | |
| Fun of (value -> value) | |
type env = (var * value) list | |
exception RecursionError | |
exception TypeError | |
let rec eval (t: term) (env: env): value = | |
match t with | |
| Lit n -> Int n | |
| Var x -> List.assoc x env | |
| Lam (x, body) -> Fun (fun v -> eval body ((x,v) :: env)) | |
| App (fnc, arg) -> (match (eval fnc env, eval arg env) with | |
| (Fun f, v) -> f v | |
| _ -> raise TypeError) | |
| Fix (x, body) -> | |
(* we could be "lazy" and immediately return a Fun here, | |
* but if you _don't_ want that things get interesting. | |
* | |
* for instance, what if the body calls "x" before yielding a function? | |
* we could: | |
* | |
* - report an error | |
* - recursively recompute body, which will probably infinite loop - | |
* unless `body` is nondeterministic! eg. imagine doing weird shit | |
* with a random number generator. | |
* | |
* here I'm just going to have it report an error in this case. | |
*) | |
let cell: (value -> value) ref = ref (fun x -> raise RecursionError) in | |
let self: value = Fun (fun x -> !cell x) in | |
match eval body ((x, self) :: env) with | |
| Fun f as v -> (cell := f; v) | |
| _ -> raise TypeError | |
let const: term = Fix ("f", Lam ("x", Lit 3)) | |
(* produces f = \x. f x, ie infinite loop *) | |
let infloop: term = Fix ("f", Var "f") | |
(* try: | |
# eval (App (const, Lit 7)) [];; | |
- : value = Int 3 | |
# eval (App (infloop, Lit 7)) [];; (* this infloops *) | |
C-c C-cInterrupted. | |
*) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
type var = string | |
type term = Var of var | |
| Lam of var * term | |
| App of term * term | |
| Fix of var * term (* only used for functions *) | |
| Lit of int | |
type value = Int of int | |
| Fun of (value -> value) | |
type env = (var * value) list | |
exception RecursionError | |
exception TypeError | |
let apply: value -> value -> value = function | |
| Fun f -> f | |
| _ -> raise TypeError | |
let rec eval (t: term) (env: env): value = | |
match t with | |
| Lit n -> Int n | |
| Var x -> List.assoc x env | |
| Lam (x, body) -> Fun (fun v -> eval body ((x,v) :: env)) | |
| App (fnc, arg) -> apply (eval fnc env) (eval arg env) | |
| Fix (x, body) -> | |
let rec callme arg = apply (eval body ((x, Fun callme) :: env)) arg | |
in Fun callme | |
let const: term = Fix ("f", Lam ("x", Lit 3)) | |
let infloop: term = Fix ("f", Var "f") | |
(* try: | |
# eval (App (const, Lit 7)) [];; | |
- : value = Int 3 | |
# eval (App (infloop, Lit 7)) [];; (* this infloops *) | |
C-c C-cInterrupted. | |
*) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
type var = string | |
type term = Var of var | |
| Lam of var * term | |
| App of term * term | |
| Fix of var * term (* only used for functions *) | |
| Lit of int | |
| Ifzero of term * term * term | |
type value = Int of int | |
| Fun of (value -> value) | |
type promise = Now of value | |
| Later of (unit -> value) | |
let force: promise -> value = | |
function Now v -> v | Later f -> f () | |
type env = (var * promise) list | |
exception RecursionError | |
exception TypeError | |
let apply: value -> value -> value = function | |
| Fun f -> f | |
| _ -> raise TypeError | |
let rec eval (t: term) (env: env): value = | |
match t with | |
| Lit n -> Int n | |
| Ifzero (cnd,thn,els) -> | |
eval (match eval cnd env with Int 0 -> thn | _ -> els) env | |
| Var x -> force (List.assoc x env) | |
| Lam (x, body) -> Fun (fun v -> eval body ((x, Now v) :: env)) | |
| App (fnc, arg) -> apply (eval fnc env) (eval arg env) | |
| Fix (x, body) -> | |
let rec self () = (print_endline "recursion!"; | |
eval body ((x, Later self) :: env)) | |
in self () | |
let const: term = Fix ("f", Lam ("x", Lit 3)) | |
let infloop: term = Fix ("f", Var "f") | |
(* f x = if x = 0 then 3 else f 0 *) | |
let constrec: term = | |
Fix ("f", Lam ("x", Ifzero (Var "x", Lit 3, App (Var "f", Lit 0)))) | |
(* try: | |
# eval (App (const, Lit 7)) [];; | |
- : value = Int 3 | |
# eval (App (constrec, Lit 7)) [];; | |
recursion! | |
recursion! | |
- : value = Int 3 | |
# eval infloop [];; (* this infloops *) | |
recursion! | |
recursion! | |
recursion! | |
recursion! | |
[...] | |
C-c C-cInterrupted. | |
*) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment