|
|
|
|
|
by siraben
2007 days ago
|
|
You can do this with the tagless-final encoding, which has a similar flavor to Data types à la carte's concept of open data types. As an example, define class ExpSYM a where
add :: a Int → a Int → a Int
lit :: Int → a Int
class MulSYM a where
mul :: a Int → a Int → a Int
Now suppose we extend with booleans and so on. We can freely combine addition and multiplication. As we add new data variants, old code need not be recompiled. We get the openness of OOP's class extensions with the flexibility of ADTs. ex1 :: (ExpSYM a, MulSYM a) => a Int
ex1 = add (lit 3) (mul (lit 4) (lit 5))
Not enough space here but you can also pattern match over final terms and interpret them in different ways (e.g. CBN vs CBV interpreters).Then as you go through your compiler pass you can see through the types that "capabilities" get reduced more and more until you reach some base language (sounds like free monads doesn't it?). Tangentially if I were to design an FP language I would use tagless final for everything, and deforest as much as I can (if possible) to reduce overhead. How this affects other aspects (e.g. automatically translating pattern matching) I have not looked into, but it's interesting nonetheless. |
|