以下是代码:
import Control.Applicative
-- newtype Parser a = Parser { runParser :: String -> [(a, String)] }
data Parser a = Parser { runParser :: String -> [(a, String)] }
instance Functor Parser where
fmap f (Parser p) = Parser (\s -> [(f x, s') | (x, s') <- p s ] )
instance Applicative Parser where
pure a = Parser (\s -> [(a, s)])
Parser q <*> Parser p = Parser (\s -> [(f x, s'') | (f, s') <- q s, (x, s'') <- p s'])
instance Alternative Parser where
empty = Parser (\s -> [])
Parser q <|> Parser p = Parser (\s -> q s ++ p s)
item = Parser (\s -> case s of
(x:xs) -> [(x, xs)]
_ -> []
)
使用当前代码,runParser (some item) "abcd"
循环,但如果Parser声明为newtype
,则它可以正常工作。
答案 0 :(得分:6)
这是获得the difference between data
and newtype
之一的好方法。这里问题的核心实际上是<|>
定义的模式匹配。
instance Alternative Parser where
empty = Parser (\s -> [])
Parser q <|> Parser p = Parser (\s -> q s ++ p s)
请记住,在运行时,newtype
与包装的类型相同。然后,当模式匹配newtype
时,GHC不做任何事情 - 没有构造函数可以评估为WNHF。
相反,当data
匹配时,看到模式Parser q
告诉GHC它需要将该解析器评估为WNHF。这是一个问题,因为some
是<|>
的无限折叠。使用data
解决问题有两种方法:
Parser
中没有<|>
个模式:
instance Alternative Parser where
empty = Parser (\s -> [])
q <|> p = Parser (\s -> runParser q s ++ runParser p s)
instance Alternative Parser where
empty = Parser (\s -> [])
~(Parser q) <|> ~(Parser p) = Parser (\s -> q s ++ p s)