Last active
March 19, 2021 18:11
-
-
Save dabrahams/e10434553803143ff4405223a7ddf451 to your computer and use it in GitHub Desktop.
From §2.1 of Sig Ager Biernacki Danvy & Midgaard: A Functional Correspondence Between Evaluators and Abstract Machines
This file contains 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
(* Exactly what appears in the paper *) | |
datatype term = IND of int (* de Bruijn index *) | |
| ABS of term | |
| APP of term * term | |
structure Eval0 | |
= struct | |
datatype denval = THUNK of unit -> expval | |
and expval = FUNCT of denval -> expval | |
(* eval : term * denval list -> expval *) | |
fun eval (IND n, e) | |
= let val (THUNK thunk) = List.nth (e, n) | |
in thunk () | |
end | |
| eval (ABS t, e) | |
= FUNCT (fn v => eval (t, v :: e)) | |
| eval (APP (t0, t1), e) | |
= let val (FUNCT f) = eval (t0, e) | |
in f (THUNK (fn () => eval (t1, e))) | |
end | |
(* main : term -> expval *) | |
fun main t = eval (t, nil) | |
end |
This file contains 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
// An unsafe translation that uses plain C unions, and | |
// doesn't show most of the problems with C++. | |
#include <utility> | |
#include <deque> | |
#include <functional> | |
struct term { | |
enum class Kind { IND, ABS, APP }; | |
Kind kind; | |
union { | |
int IND; // de Bruijn index | |
term* ABS; | |
std::pair<term*, term*> APP; | |
}; | |
}; | |
struct expval; | |
struct denval { std::function<auto () -> expval> THUNK; }; | |
struct expval { std::function<auto (denval) -> expval> FUNCT; }; | |
template <class T> auto prepend(T e, std::deque<T> v) -> std::deque<T> { | |
v.push_front(e); | |
return v; | |
} | |
auto eval(term t, std::deque<denval> e) -> expval { | |
switch (t.kind) { | |
case term::Kind::IND: | |
return e[t.IND].THUNK(); | |
case term::Kind::ABS: { | |
auto t0 = *t.ABS; | |
return { [=](denval v){ return eval(t0, prepend(v, e)); } }; | |
} | |
case term::Kind::APP: | |
auto [t0, t1] = t.APP; | |
auto f = eval(*t0, e).FUNCT; | |
return f({ [=,t1=t1](){ return eval(*t1, e); } }); | |
} | |
} | |
auto main1(term t) -> expval { return eval(t, std::deque<denval>()); } | |
auto main() -> int {} |
This file contains 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
// An extremely literal translation of what's in the paper | |
indirect enum term { | |
case IND(Int) // de Bruijn index | |
case ABS(term) | |
case APP(term, term) | |
} | |
enum denval { case THUNK(()->expval) } | |
enum expval { case FUNCT((denval)->expval) } | |
func eval(_ t: term, _ p: [denval]) -> expval { | |
switch (t, p) { | |
case let (.IND(n), e): | |
if case let .THUNK(thunk) = e[n] { | |
return thunk() | |
} | |
case let (.ABS(t0), e): | |
return .FUNCT({ v in eval(t0, [v] + e) }) | |
case let (.APP(t0, t1), e): | |
if case let .FUNCT(f) = eval(t0, e) { | |
return f(.THUNK({ eval(t1, e) })) | |
} | |
} | |
fatalError("unreachable") // because we used if case to unwrap denval/expval. | |
} | |
func main(_ t: term) -> expval { eval(t, []) } |
This file contains 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
// Like swift1, but we unwrap denval and expval with a switch | |
indirect enum term { | |
case IND(Int) // de Bruijn index | |
case ABS(term) | |
case APP(term, term) | |
} | |
enum denval { case THUNK(()->expval) } | |
enum expval { case FUNCT((denval)->expval) } | |
func eval(_ t: term, _ p: [denval]) -> expval { | |
switch (t, p) { | |
case let (.IND(n), e): | |
switch e[n] { case let .THUNK(thunk): | |
return thunk() | |
} | |
case let (.ABS(t0), e): | |
return .FUNCT({ v in eval(t0, [v] + e) }) | |
case let (.APP(t0, t1), e): | |
switch eval(t0, e) { case let .FUNCT(f): | |
return f(.THUNK({ eval(t1, e) })) | |
} | |
} | |
} | |
func main(_ t: term) -> expval { eval(t, []) } |
This file contains 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
// unary enums (denval/expval) are a bit awkward in Swift; use structs instead. | |
indirect enum term { | |
case IND(Int) // de Bruijn index | |
case ABS(term) | |
case APP(term, term) | |
} | |
struct denval { let THUNK: ()->expval } | |
struct expval { let FUNCT: (denval)->expval } | |
func eval(_ t: term, _ p: [denval]) -> expval { | |
switch (t, p) { | |
case let (.IND(n), e): | |
return e[n].THUNK() | |
case let (.ABS(t0), e): | |
return .init(FUNCT: { v in eval(t0, [v] + e) }) | |
case let (.APP(t0, t1), e): | |
let f = eval(t0, e).FUNCT | |
return f(.init(THUNK: { eval(t1, e) })) | |
} | |
} | |
func main(_ t: term) -> expval { eval(t, []) } |
This file contains 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
// Eliminate needless pattern matching | |
indirect enum term { | |
case IND(Int) // de Bruijn index | |
case ABS(term) | |
case APP(term, term) | |
} | |
struct denval { let THUNK: ()->expval } | |
struct expval { let FUNCT: (denval)->expval } | |
func eval(_ t: term, _ e: [denval]) -> expval { | |
switch t { | |
case let .IND(n): | |
return e[n].THUNK() | |
case let .ABS(t0): | |
return .init(FUNCT: { v in eval(t0, [v] + e) }) | |
case let .APP(t0, t1): | |
let f = eval(t0, e).FUNCT | |
return f(.init(THUNK: { eval(t1, e) })) | |
} | |
} | |
func main(_ t: term) -> expval { eval(t, []) } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment