Hacker News new | past | comments | ask | show | jobs | submit login

For any one interested in what's going on here, the approach is roughly this:

* Create some basic tokens that represent operations in some domain

* Define an interpreter for those tokens, ie., the operation each token corresponds to

* Define a program as a sequence of these tokens

* Evaluate the program

To make this somewhat more efficient and correct, you can use the type system to define the tokens (eg., `interface ADD {}` becomes the `ADD` token). And use generics to sequence the tokens (eg., `ADD< ADD<CONST, CONST>, ...>`) with the runtime still having the actual values (so, roughly, `ADD<CONST, CONST> = new ADD(10, 10)`).

Then the interpreter becomes unwrapping those types in the order they're sequenced, extracting the actual runtime-held value, and performing the relevant operation (here, eg., adding two numbers).

If this seems an insane thing to do: it is. It becomes midly less insane if you have a syntax to do it in easily, and if your compiler is aware that you're doing it (ie., haskell).

Some much more basic version of this could be useful, in a real-world system, as a compile-time alternative to what might otherwise be a stringly-typed DSL.

Eg., program = [new Search<Query>("blah"), ...]; run(program)




Well summarized. This general approach (create tokens/interpreter for tokens/program as token tree) can be found in other functional design patterns too, like the Free Monad pattern. Even decoupled from any one specific design pattern, I find myself reaching for this general approach when modeling a complex domain.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: