Ich versuche, eine EDSL in Haskell zu implementieren. Ich würde gerne den AST mit den Variablennamen, die gebunden sind, ausdrucken (wenn ich die echten Namen nicht bekommen kann, würden einige generierte Namen genügen).Drucken eines AST mit Variablennamen
Dieses, wie weit ich mit einem einfachen Beispiel bekam:
import Control.Monad.State
data Free f a = Roll (f (Free f a))
| Pure a
instance Functor f => Monad (Free f) where
return = Pure
(Pure a) >>= f = f a
(Roll f) >>= g = Roll $ fmap (>>= g) f
data Expr a = I a
| Plus (Expr a) (Expr a)
deriving (Show)
data StackProgram a next = Pop (a -> next)
| Push a next
instance Functor (StackProgram a) where
fmap f (Pop k) = Pop (f.k)
fmap f (Push i x) = Push i (f x)
liftF :: Functor f => f a -> Free f a
liftF l = Roll $ fmap return l
push :: a -> Free (StackProgram a)()
push i = liftF $ Push i()
pop :: Free (StackProgram a) a
pop = liftF $ Pop id
prog3 :: Free (StackProgram (Expr Int)) (Expr Int)
prog3 = do
push (I 3)
push (I 4)
a <- pop
b <- pop
return (Plus a b)
showSP' :: (Show a, Show b) => Free (StackProgram a) b -> [a] -> State Int String
showSP' (Pure a) _ = return $ "return " ++ show a
showSP' (Roll (Pop f)) (a:stack) = do
i <- get
put (i+1)
rest <- showSP' (f a) stack
return $ "var" ++ show i ++ " <- pop " ++ show (a:stack) ++ "\n" ++ rest
showSP' (Roll (Push i n)) stack = do
rest <- showSP' n (i:stack)
return $ "push " ++ show i ++ " " ++ show stack ++ "\n" ++ rest
showSP :: (Show a, Show b) => Free (StackProgram a) b -> [a] -> String
showSP prg stk = fst $ runState (showSP' prg stk) 0
Laufen ergibt dies:
*Main> putStrLn $ showSP prog3 []
push I 3 []
push I 4 [I 3]
var0 <- pop [I 4,I 3]
var1 <- pop [I 3]
return Plus (I 4) (I 3)
Also, was ich will ist Plus (I 4) (I 3)
mit Plus var0 var1
zu ersetzen. Ich habe darüber nachgedacht, durch den Rest des Baums zu gehen und die gebundenen Variablen durch Namen-Wert-Tupel zu ersetzen, aber ich bin mir nicht 100% sicher, ob/wie das funktionieren würde. Ich würde es auch vorziehen, die ursprünglichen Variablennamen zu behalten, aber ich kann mir keine einfache Möglichkeit vorstellen, dies zu tun. Ich hätte lieber eine ziemlich leichte Syntax in Haskell (so wie oben).
Ich würde auch gerne Hinweise auf Material, das mich lehrt, wie man diese Art von Dingen zu tun. Ich habe ein bisschen über freie Monaden und GADTs gelesen, aber ich denke, ich vermisse es, alles zusammen zu setzen.
Haben Sie darüber nachgedacht, eine vorhandene Bibliothek mit [wie diese] (http: //hackage.haskell. org/package/gebunden) statt? –
@C.A.McCann Ich war mir dessen nicht bewusst. Danke für den Zeiger. – Paul
Check out [diese Antwort] (http://stackoverflow.com/a/14084654/1026598) Ich gab eine ähnliche Frage. Ist das nahe daran, was Sie vorhatten? –