“在Haskell中编程”在sat函数中出错

时间:2010-04-09 12:52:00

标签: haskell

我在Graham Hutton的Haskell编程的第8章中,我正在复制代码并在GHC中对其进行测试。

请参阅此处的幻灯片:http://www.cis.syr.edu/~sueo/cis352/chapter8.pdf,特别是幻灯片15

到目前为止我复制的相关代码是:

type Parser a = String -> [(a, String)]
pih_return :: a -> Parser a
pih_return v = \inp -> [(v, inp)]
failure :: Parser a
failure = \inp -> []
item :: Parser Char
item = \inp -> case inp of
                    [] -> []
        (x:xs) -> [(x,xs)]
parse :: Parser a -> String -> [(a, String)]
parse p inp = p inp
sat :: (Char -> Bool) -> Parser Char
sat p = do x <- item
           if p x then pih_return x else failure

我已将书中的return功能名称更改为pih_return,以便它不会与Prelude return功能发生冲突。

错误位于最后一个函数sat中。我直接从书中复制了这个。

您可能会看到pCharBool的函数(例如isDigit),而x的类型为[(Char, String)] ,这是第一个错误。

然后pih_return获取值v并返回[(v, inp)],其中inpString。这会导致sat出错,因为传递的vx,而不是Char

通过明确将inp加入sat

,我提出了这个解决方案
sat :: (Char -> Bool) -> Parser Char
sat p inp = do x <- item inp
               if p (fst x) then pih_return (fst x) inp else failure inp

这是解决问题的最佳方法吗?

4 个答案:

答案 0 :(得分:5)

第一个sat无效,Parser必须是monad才能使用do表示法。为了使它成为monad实例,必须使用newtype

我不拥有这本书,但我想作者想要从一个简单的解析器类型开始,然后将它扩展为一个完整的monad,我怀疑你已经将非monadic版本的定义混淆了Parser monad(sat)并错过了monad实例声明。

可用章节中的代码on the author's web site,其中为Parser定义了monad实例。

如果你必须为简单的sat类型写一个Parser函数,我宁愿用lambda风格(如item)来做,并完全避免monad(你注意到了原始sat的{​​{1}}块是do monad,你的是Parser monad?)。我认为您的List版本中存在错误:而不是sat,我认为它应该是pih_return (fst x) inp

答案 1 :(得分:2)

如果没有monad,则无法使用do表示法,除非使用datanewtype,否则无法创建monad实例,并且无法使用{{ 1}}或data除非你引入恼人的值构造函数。毫无疑问,值构造函数已被省略,因为它 令人讨厌。

在下面的示例中,您可以看到我使用了newtype并引入了恼人的值构造函数newtype。这是使Parser声明有效的原因,此时您不仅可以使用instance - 符号,还可以使用标准monadic doreturn

此代码编译时没有错误或警告:

fail

答案 2 :(得分:1)

幻灯片缺少类型Monad的{​​{1}}类型类的实现。

使用该声明,Parser表示法是正确的; do实际上正确地从x <- item展开到[(Char, String)]

我似乎没有得到这个定义而没有编译它以查看错误但它是一个开始:

(Char, String)

答案 3 :(得分:1)

我正在阅读同一本书,并在尝试做练习时遇到了同样的问题。我从使用'do ...'符号恢复到&gt;&gt; =。对于任何有兴趣的人,我将我的代码包含在使用nat函数中。我将所有函数添加到a并更改了&gt;&gt; = to&gt;&gt;&gt; =以避免名称与prelude碰撞。

type AParser a = String -> [(a, String)]
areturn :: a -> AParser a
areturn v = \inp -> [(v, inp)]
afailure :: AParser a
afailure = \inp -> []
aitem :: AParser Char
aitem = \inp -> case inp of
                  [] -> []
                  (x:xs) -> [(x, xs)]
aparse :: AParser a -> String -> [(a, String)]
aparse p inp = p inp
(>>>=) :: AParser a -> (a -> AParser b) -> AParser b
p >>>= f = \inp -> case aparse p inp of
                    [] -> []
                    [(v, out)] -> aparse (f v) out
(+++) :: AParser a -> AParser a -> AParser a
p +++ q = \inp -> case aparse p inp of
                    [] -> aparse q inp
                    [(v, out)] -> [(v, out)]
asat :: (Char -> Bool) -> AParser Char
asat p = aitem >>>= (\x -> if p x then areturn x else afailure)
adigit :: AParser Char
adigit = asat isDigit
amany :: AParser a -> AParser [a]
amany p = amany1 p +++ areturn []
amany1 :: AParser a -> AParser [a]
amany1 p = p >>>= (\v -> (amany p) >>>= (\vs -> areturn (v:vs)))
anat :: AParser Int
anat = amany1 adigit >>>= (\xs -> areturn (read xs))