Haskell 具有变形的单子解析器
Haskell monadic parser with anamorphisms
我的问题是如何将递归的 F 代数式递归类型定义与 monadic/applicative-style 解析器结合起来,以扩展到实际的编程语言。
我刚刚开始使用下面的 Expr
定义:
data ExprF a = Plus a a |
Val Integer deriving (Functor,Show)
data Rec f = In (f (Rec f))
type Expr = Rec ExprF
我正在尝试将它与使用变形的解析器结合起来:
ana :: Functor f => (a -> f a) -> a -> Rec f
ana psi x = In $ fmap (ana psi) (psi x)
parser = ana psi
where psi :: String -> ExprF String
psi = ???
据我所知,在我的示例中,psi
应该只解析一个整数,或者它应该决定字符串是 <expr> + <expr>
然后(通过递归调用 fmap (ana psi)
), 它应该解析左侧和右侧的表达式。
但是,(monadic/applicative) 个解析器不是这样工作的:
- 他们首先尝试解析左边的表达式,
+
,
- 和右边的表达式
我看到的一个解决方案是将 Plus a a
的类型定义更改为 Plus Integer a
,以反映解析过程,但这似乎不是最佳途径。
欢迎提出任何建议(或阅读指南)!
如果你需要一个 monadic 解析器,你需要一个 monad in your unfold:
anaM :: (Traversable f, Monad m) => (a -> m (f a)) -> a -> m (Rec f)
anaM psiM x = In <$> (psiM x >>= traverse (anaM psiM))
然后你可以像这样编写只解析 ExprF
一级的东西:
parseNum :: Parser Integer
parseNum = -- ...
char :: Char -> Parser Char
char c = -- ...
parseExprF :: Maybe Integer -> Parser (ExprF (Maybe Integer))
parseExprF (Just n) = pure (Val n)
parseExprF Nothing = do
n <- parseNum
empty
<|> (Plus (Just n) Nothing <$ char '+')
<|> (pure (Val n))
鉴于此,您现在有了递归 Expr
解析器:
parseExpr :: Parser Expr
parseExpr = anaM parseExprF Nothing
当然,对于 ExprF
,您将需要 Foldable
和 Traversable
的实例,但是编译器可以为您编写这些实例,它们本身不是递归的。
我的问题是如何将递归的 F 代数式递归类型定义与 monadic/applicative-style 解析器结合起来,以扩展到实际的编程语言。
我刚刚开始使用下面的 Expr
定义:
data ExprF a = Plus a a |
Val Integer deriving (Functor,Show)
data Rec f = In (f (Rec f))
type Expr = Rec ExprF
我正在尝试将它与使用变形的解析器结合起来:
ana :: Functor f => (a -> f a) -> a -> Rec f
ana psi x = In $ fmap (ana psi) (psi x)
parser = ana psi
where psi :: String -> ExprF String
psi = ???
据我所知,在我的示例中,psi
应该只解析一个整数,或者它应该决定字符串是 <expr> + <expr>
然后(通过递归调用 fmap (ana psi)
), 它应该解析左侧和右侧的表达式。
但是,(monadic/applicative) 个解析器不是这样工作的:
- 他们首先尝试解析左边的表达式,
+
,- 和右边的表达式
我看到的一个解决方案是将 Plus a a
的类型定义更改为 Plus Integer a
,以反映解析过程,但这似乎不是最佳途径。
欢迎提出任何建议(或阅读指南)!
如果你需要一个 monadic 解析器,你需要一个 monad in your unfold:
anaM :: (Traversable f, Monad m) => (a -> m (f a)) -> a -> m (Rec f)
anaM psiM x = In <$> (psiM x >>= traverse (anaM psiM))
然后你可以像这样编写只解析 ExprF
一级的东西:
parseNum :: Parser Integer
parseNum = -- ...
char :: Char -> Parser Char
char c = -- ...
parseExprF :: Maybe Integer -> Parser (ExprF (Maybe Integer))
parseExprF (Just n) = pure (Val n)
parseExprF Nothing = do
n <- parseNum
empty
<|> (Plus (Just n) Nothing <$ char '+')
<|> (pure (Val n))
鉴于此,您现在有了递归 Expr
解析器:
parseExpr :: Parser Expr
parseExpr = anaM parseExprF Nothing
当然,对于 ExprF
,您将需要 Foldable
和 Traversable
的实例,但是编译器可以为您编写这些实例,它们本身不是递归的。