I was inspired by the recent activities of the Haskell 1 blog to try my hand at writing Forth-like DSL in Haskell. The approach that I took is both simple and confusing:
{-
For simple things, this works pretty well:
start :: (() -> r) -> r start f = f () end :: (() :> a) -> a end (() :> a) = a stack xf = fx runF s = s end _1 = liftS0 1 neg = liftS1 negate add = liftS2 (+) -- aka "push" liftS0 :: a -> (s :~> (s :> a)) liftS0 as = stack $ s :> a liftS1 :: (a -> b) -> ((s :> a) :~> (s :> b)) liftS1 f (s :> a) = stack $ s :> fa liftS2 :: (a -> b -> c) -> ((s :> a :> b) :~> (s :> c)) liftS2 f (s :> a :> b) = stack $ s :> fab
Simple functions can be trivially converted to corresponding stack transformations. Some game around gives nice results so far:
ghci> runF $ start _1 _1 neg add 0
The problem arises when I try to extend it with higher order functions.
-- this requires ImpredicativeTypes...not really sure what that means -- also this implementation seems way too simple to be correct -- though it does typecheck. I arrived at this after pouring over types -- and finally eta-reducing the (s' -> r) function argument out of the equation -- call (a :> f) h = fah call :: (s :> (s :~> s')) :~> s' call (a :> f) = fa
call should convert the form stack (s :> (s :~> s')) to form s , essentially "applying" the transformation (held on top of the stack) to "rest" it. I believe that should work as follows:
ghci> runF $ start _1 (liftS0 neg) call -1
But actually it gives me a huge type mismatch error. What am I doing wrong? Can the stack transform view handle higher-order functions, or do I need to adjust it?
1 NB Unlike the way these guys did it, instead of start push 1 push 2 add end , I want it to be runF $ start (push 1) (push 2) add , the idea is that maybe later I can work with a mask of type typeclass to make push implicit for certain literals.
polymorphism haskell higher-order-functions impredicativetypes concatenative-language
Dan burton
source share