u/AdOdd5690

▲ 34 r/lisp+1 crossposts

I've been working on a small reflective language called Blue, inspired by Kenichi Asai's Black. Blue is built in Haskell, and the reflection mechanism is straightforward: an em operator that lifts a Blue expression into Haskell and evaluates it through the host:

baseEval (EM e) = metaEval e

metaEval :: Expr -> Eval Value
metaEval e = Eval $ lift $ interpret
    ("toValue (" ++ toHaskell e ++ ")") (as :: Value)

em pretty-prints the AST, hands it to hint, and lifts the result back into a Blue Value. Right now em only handles the same forms baseEval handles, so for the moment it's close to an expensive identity function:

BLUE> em 2 + 3
5
BLUE> em if true then 100 else 0
100

The point of having the mechanism in place first is that Value and toHaskell are the bottleneck, not the host. Once I extend Value with cases for lists, lambdas, or floats thenem immediately reaches whatever in Haskell produces those types, without changing the evaluator. So the next steps are extending the value domain rather than touching reflection itself.

A few things I haven't worked out:

I don't know the literature for reflection-via-host-eval specifically. Smith's 3-Lisp and Black expose the evaluator itself rather than delegating to the host. Pointers welcome.

hint is heavy. It's fine while reflection is rare, but if em becomes load-bearing this probably wants to be staged compilation via Template Haskell. Curious whether anyone has built something analogous that way.

Once a program crosses through em, the host can return whatever it likes; I'm informally trusting the result is a well-formed Value. There's probably a clean framing in terms of contracts but I haven't written it down.

Repo: https://github.com/ih1d/blue

reddit.com
u/AdOdd5690 — 8 days ago