Note: I noticed this was posted to /r/programming but it's far from complete, it doesn't even have numbers or let/if/case special operators. It was just a Friday evening's whim to research whether quotation can be practically statically typed and what that might feel like. I'll have to implement at least case and let in order to deconstruct the quoted expressions and implement eval similar to Roots of Lisp before I can answer that to my satisfaction.
--
Basic unit type:
λ> replTy "()"
() :: ()Basic functions:
λ> replTy "(fn x x)"
(fn x x) :: b -> b
λ> replTy "((fn x ()) (fn x x))"
((fn x ()) (fn x x)) :: ()
λ> repl "((fn x x) (fn x x))"
((fn x x) (fn x x)) :: c -> c
(fn x x)Statically typed:
λ> repl "(() (fn x x))"
-- *** Exception: Couldn't match expected type: ()
-- against type: (b -> b) -> eStandard quotation:
λ> replTy "'()"
'() :: 'Symbol
λ> repl "'(foo bar)"
'(foo bar) :: 'Symbol
(foo bar)Statically typed quotation:
λ> replTy "~()"
~() :: '()All quotes have type 'a. Normal symbolic Lisp style is 'Symbol,
quoting anything else, e.g. for unit, is '(). Also things have to be
in scope:
λ> repl "~a"
-- *** Exception: Not in scope: `a'Quoted function:
λ> replTy "'(fn x x)"
'(fn x x) :: 'SymbolQuoted function:
λ> replTy "~(fn x x)"
~(fn x x) :: '(b -> b)Notice the type is '(b -> b).
There's an eval function:
λ> replTy "eval"
eval :: 'a -> aIt accepts a quoted a and returns the a that it represents. It
won't accept anything not quoted:
λ> replTy "(eval ())"
-- *** Exception: Couldn't match expected type: 'a
-- against type: ()If given a symbolic quoted expression, it will just return it as-is:
λ> repl "(eval '())"
(eval '()) :: Symbol
()
λ> repl "(eval '((fn x x) '()))"
(eval '((fn x x) '())) :: Symbol
((fn x x) ())Given a well-typed quoted expression it will run the code:
λ> repl "(eval ~((fn x x) '()))"
(eval ~((fn x x) '())) :: 'Symbol
()
λ> repl "(eval ~((fn x x) ()))"
(eval ~((fn x x) ())) :: ()
()
That's a very hard problem you're tackling here. Lisps can usually write self-interpreters, but typed self-interpreters are very hard (the usual conjecture is they don't exist for usual type systems, as a consequence of Gödel's theorems).* Providing
evalas a builtin is one of the ways out, but then it's less clear that you can achieve other metaprogramming tasks — writingevalin the language is a kind of benchmark for its metaprogramming power.*Should you want to read academic papers on how to do it, see papers at PLDI '09 (https://www.uni-marburg.de/fb12/ps/research/tsr?set_language=en) and POPL '15 ("Self-Representation in Girard's System U", not yet publicly available).