Haskell 用parsec解析递归数据 import Data.Attoparsec.Text.Lazy 导入Data.Text.Lazy.Internal(文本) 导入Data.Text.Lazy(包) 数据列表a=零| Cons a(列表a) 列表::文本 列表=打包$unlines [ "0" , "1" , "2" , "5" ]

Haskell 用parsec解析递归数据 import Data.Attoparsec.Text.Lazy 导入Data.Text.Lazy.Internal(文本) 导入Data.Text.Lazy(包) 数据列表a=零| Cons a(列表a) 列表::文本 列表=打包$unlines [ "0" , "1" , "2" , "5" ],haskell,parsec,recursive-datastructures,attoparsec,Haskell,Parsec,Recursive Datastructures,Attoparsec,如何实现List Int解析器从List解析Cons 0(Cons 1(Cons 2(Cons 5 Nil)) ps:不解析[Int]并将其转换为列表Int的纯解析器更可取。如下: import Control.Applicative -- rest of imports as in question data List a = Nil | Cons a (List a) deriving Show -- for testing -- definition of list as in q

如何实现
List Int
解析器从
List
解析
Cons 0(Cons 1(Cons 2(Cons 5 Nil))

ps:不解析
[Int]
并将其转换为
列表Int
的纯解析器更可取。

如下:

import Control.Applicative
-- rest of imports as in question

data List a = Nil | Cons a (List a)
  deriving Show -- for testing

-- definition of list as in question

parseList :: Parser (List Int)
parseList = foldr Cons Nil <$> many (decimal <* endOfLine)

我认为我们可以通过检查:

我们可以制作自己的类似变体:

many'' :: (MonadPlus m) => m a -> m (List a)
many'' p = many_p
  where
    many_p = some_p `mplus` return Nil
    some_p = liftM2 Cons p many_p
并将其应用于任何一元解析器

(请注意,
many'
使用了它自己的,在第一个操作的结果中是严格的。它不是由模块导出的,所以我使用了普通的
liftM2

或者我们可以制作一个更通用的变体,使用
备选方案

many'' :: (Alternative f) => f a -> f (List a)
many'' p = many_p
  where
    many_p = some_p <|> pure Nil
    some_p = Cons <$> p <*> many_p
many'::(备选方案f)=>fa->f(列表a)
多个“”p=多个
哪里
多=一些纯零
有些=缺点许多

无需从INT列表转换:

import Data.Attoparsec.Text.Lazy
import Data.Text.Lazy (Text, pack)
import Control.Applicative

data List a = Nil | Cons a (List a)
  deriving Show

input :: Text
input = pack $ unlines [ "0", "1", "2", "5"]

list :: Parser (List Int)
list = cons <|> nil
  where
    cons = Cons <$> (decimal <* endOfLine) <*> list
    nil  = pure Nil 

main = print $ parse list input
import Data.Attoparsec.Text.Lazy
导入Data.Text.Lazy(文本,包)
导入控制
数据列表a=零| Cons a(列表a)
衍生节目
输入::文本
输入=组合$unlines[“0”、“1”、“2”、“5”]
解析器(list Int)
列表=零
哪里

cons=cons(decimal正如其他人所指出的,您实际上不需要使用递归(尽管您可以)来解析列表。但是如果您要解析递归语法,您可以在解析器中使用递归(参见bzn的答案和Petr的答案),也可以在解析器的结果上递归(类似于Markdown中的嵌套)。我在这里介绍了后者:

这是可编译的还是甚至是可类型检查的?哦,对不起。我重命名了解析器,使其与kosmikus answer中的名称相同,但忘记了在
where
-子句中这样做。编辑为可编译。根据请求,这实际上是一个递归解析器。
many'' :: (Alternative f) => f a -> f (List a)
many'' p = many_p
  where
    many_p = some_p <|> pure Nil
    some_p = Cons <$> p <*> many_p
import Data.Attoparsec.Text.Lazy
import Data.Text.Lazy (Text, pack)
import Control.Applicative

data List a = Nil | Cons a (List a)
  deriving Show

input :: Text
input = pack $ unlines [ "0", "1", "2", "5"]

list :: Parser (List Int)
list = cons <|> nil
  where
    cons = Cons <$> (decimal <* endOfLine) <*> list
    nil  = pure Nil 

main = print $ parse list input