4

我在 Haskell 中实现了一个简单的解释器,但我遇到了这个问题。代码是这样的:

import Control.Applicative
import Data.Char

newtype Parser a = P (String -> [(a,String)])

parse :: Parser a -> String -> [(a,String)]
parse (P p) inp = p inp

item :: Parser Char
item = P (\inp -> case inp of
    [] -> []
    (x:xs) -> [(x,xs)])

instance Functor Parser where
fmap :: (a -> b) -> Parser a -> Parser b
fmap g p = P (\inp -> case parse p inp of
    [] -> []
    [(v,out)] -> [(g v, out)])

instance Monad Parser where
(>>=) :: Parser a -> (a -> Parser b) -> Parser b
p >>= f = P (\inp -> case parse p inp of
    [] -> []
    [(v,out)] -> parse (f v) out)

three :: Parser (Char,Char)
three = do {x <- item;
    item;
    z <- item;
    return (x,z);}

如果我在拥抱中运行脚本,一切似乎都很好。但是当我尝试运行命令时

parse three "abcdef"

我收到一个错误:

Program error: undefined member: >>=

请问有人可以帮我吗?

4

2 回答 2

3
  1. 不要给实例类型签名。

  2. 缩进实例定义。

在这两件事之后你会看到一个新的错误,你需要定义一个 Applicative 实例,因为class Applicative m => Monad m.

编辑:

你写了:

instance Monad Parser where
(>>=) :: Parser a -> (a -> Parser b) -> Parser b    -- This is a type signature
p >>= f = P (\inp -> case parse p inp of   -- This is the definition
    [] -> []
    [(v,out)] -> parse (f v) out)

第一个问题是类型签名,我在上面的评论中注意到了这一点。去掉它:

instance Monad Parser where
p >>= f = P (\inp -> case parse p inp of   -- This is the definition
    [] -> []
    [(v,out)] -> parse (f v) out)

第二个问题是缩进。您必须缩进成员函数定义(或使用花括号,但这是一种不常见的样式):

instance Monad Parser where
    p >>= f = P (\inp -> case parse p inp of
       [] -> []
       [(v,out)] -> parse (f v) out)

现在你得到一个新的错误,说你需要一个应用实例。所以你需要:

instance Applicative Parser where
    pure = ...
    (<*>) = ...

甚至在那之后它会告诉你为 Functor 编写一个实例。

于 2018-12-12T14:57:06.183 回答
2

声明实例时不要显式编写类型。但是,如果您真的想这样做,请转InstanceSigs扩展:{-# LANGUAGE InstanceSigs #-}

正如另一个答案中提到的,Haskell 是缩进敏感的,但是您可以将定义放在括号中以绕过它:

instance SomeClass Int where {
x = 3
}
于 2018-12-12T15:08:33.093 回答