Tôi đang cố triển khai EDSL trong Haskell. Tôi muốn in đẹp AST với tên biến bị ràng buộc (nếu tôi không thể có được tên thật thì một số tên được tạo ra sẽ làm).In một AST có tên biến
Đây là cách nay tôi đã có với một ví dụ đơn giản:
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
Chạy điều này mang lại:
*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)
Vì vậy, những gì tôi muốn là để thay thế Plus (I 4) (I 3)
với Plus var0 var1
. Tôi đã nghĩ về việc đi qua phần còn lại của cây và thay thế các biến bị ràng buộc bằng các giá trị tên-giá trị, nhưng tôi không chắc chắn 100% nếu/làm thế nào có thể hoạt động. Tôi cũng muốn giữ tên biến ban đầu, nhưng tôi không thể nghĩ ra một cách dễ dàng để làm điều này. Tôi muốn có một cú pháp khá nhẹ trong haskell (loại như trên).
Tôi cũng đánh giá cao các chỉ dẫn cho tài liệu dạy tôi cách làm tốt nhất những thứ này. Tôi đã đọc một chút về monads miễn phí và GADT, nhưng tôi đoán tôi đang thiếu cách để đặt tất cả lại với nhau.
Bạn đã xem là sử dụng một thư viện hiện [như thế này] (http: //hackage.haskell. org/package/bound) thay vào đó? –
@ C.A.McCann Tôi không biết về nó. Cảm ơn bạn cho con trỏ. – Paul
Kiểm tra [câu trả lời này] (http://stackoverflow.com/a/14084654/1026598) Tôi đã đưa ra một câu hỏi tương tự. Đó có phải là gần với những gì bạn đã có trong tâm trí? –