我想了解Parsers。因此我创建了自己的解析器。不幸的是它不起作用。为什么?
type Parser a = String -> [(a, String)]
preturn :: a -> Parser a
preturn t = \inp -> [(t,inp)]
pfailure :: Parser a
pfailure = \inp -> []
pitem :: Parser Char
pitem = \inp -> case inp of
[] -> []
(x:xs) -> [(x,xs)]
parse :: Parser a -> Parser a
--parse :: Parser a -> String -> [(a,String)]
parse p inp = p inp
{-
combine :: Parser a -> Parser b -> Parser (a,b)
combine p1 p2 = \inp -> p2 t output
where
p1 inp = ([
-}
-- firstlast :: Parser (Char,Char)
firstlast = do
x <- pitem
z <- pitem
y <- pitem
preturn (x,y)
another = do
x <- pitem
y <- pitem
Firstlast应该接受一个字符串并返回第一个和第三个字符。不幸的是,它返回奇数值,并且它不接受它的类型(Parser(Char,Char))
例如,
*Main> firstlast "abc"
[(([('a',"bc")],[('a',"bc")]),"abc")]
应该发生的事情是:
*Main> firstlast "abc"
[("ac",[])]
答案 0 :(得分:7)
请使用编译的代码。您的another
功能没有。
firstlast
和another
的代码使用了do
- 符号。你在这里使用pitem
的方式,看起来好像你期望Parser
成为一个monad。但事实并非如此,至少不像你期望的那样。
预定义的monad实例使GHC认为Parser
是monad,即
instance Monad ((->) r) where
return = const
f >>= k = \ r -> k (f r) r
这个实例说的是,对于任何类型r
,函数类型r -> ...
都可以被认为是monad,即通过在任何地方分配参数。因此,返回此monad中的某些内容相当于生成忽略类型r
的参数的值,并且绑定值意味着您将r
并将其传递给左右计算。
这不是您想要的解析器。输入字符串将分发给所有计算。因此每个pitem
将对原始输入字符串进行操作。此外,正如
pitem :: String -> [(Char, String)]
您的monadic计算结果将为[(Char, String)]
类型,因此x
和y
都属于此类型。这就是你得到结果的原因
[(([('a',"bc")],[('a',"bc")]),"abc")]
您在同一输入字符串上调用pitem
三次。你把两个结果放在一对中,你就是preturn
整个事情。
您需要为Parser
类型定义自己的monad实例。您无法直接执行此操作,因为Parser
是类型同义词,并且无法部分应用类型同义词,
所以你不能写
instance Monad Parser where
...
相反,您必须将Parser
包装在新的数据类型或newtype中:
newtype Parser a = Parser { parse :: String -> [(a, String)] }
这为您提供了一个构造函数Parser
和一个函数parse
,用于在展开和包装的解析器类型之间进行转换:
Parser :: String -> [(a, String)] -> Parser a
parse :: Parser a -> String -> [(a, String)]
这意味着您必须调整其他功能。例如,preturn
变为
preturn :: a -> Parser a
preturn t = Parser (\inp -> [(t,inp)])
同样更改pfailure
和pitem
。然后,您必须定义Monad
实例:
instance Monad Parser where
return = preturn
(>>=) = ... -- to be completed by you
上面的代码中不包含函数(>>=)
。您将希望实现将输入传递给第一个解析器的行为,并且对于每个结果,结果和剩余的输入将传递给(>>=)
的第二个参数。完成此操作后,对parse firstlast "abc"
的调用将产生以下结果:
[(('a','c'),"")]
这不是你想要的问题,但我相信这是你真正想要的。