Я нахожусь в главе 8 Программирования Graham Hutton в Haskell, и я копирую код и тестирую его в 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
так, чтобы это не сталкивалось с Вводной частью return
функция.
Ошибки находятся в последней функции sat
. Я скопировал это непосредственно с книги.
Поскольку можно, вероятно, видеть p
функция от Char
кому: Bool
(например. isDigit
) и x
имеет тип [(Char, String)]
, таким образом, это - первая ошибка.
Затем pih_return
принимает значение v
и возвраты [(v, inp)]
где inp
a String
. Это вызывает ошибку в sat
потому что v
быть переданным x
который не является a 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
Действительно ли это - лучший способ решить проблему?
Первый sat
не может работать, Parser
должен быть монадой, чтобы использовать ] do
обозначение. Чтобы сделать его экземпляром монады, необходимо использовать newtype
.
Мне не принадлежит книга, но я полагаю, что автор хотел начать с простого типа синтаксического анализатора, а затем расширить его до полной монады, и я подозреваю, что вы перепутали определения немонадических версий с одним из монада парсера
( sat
) и пропустила объявление экземпляра монады по пути.
Есть код из главы , доступной на веб-сайте автора , где экземпляр монады был определен для Parser
.
Если вам нужно написать функцию sat
для простого типа Parser
, я бы предпочел использовать лямбда-стиль (как элемент
) и избегать монад. полностью (вы заметили, что исходный блок sat
do
был монадой Parser
, а ваш - монадой List
?). И я думаю у вас есть ошибка в вашей sat
версии: вместо pih_return (fst x) inp
, я думаю, это должно быть pih_return (fst x) (snd x)
.
Вы не можете использовать нотацию do
без монады, и вы не можете создать экземпляр монады, если не используете data
или newtype
, и вы не можете использовать data
или newtype
, если не введете раздражающий конструктор значений. Несомненно, конструктор значения был опущен только потому, что он раздражает.
В приведенном ниже примере вы можете видеть, что я использовал newtype
и ввел раздражающий конструктор значений Parser
. Это то, что заставляет объявление экземпляра
работать, и на этом этапе вы можете использовать не только нотацию do
, но и стандартные монадические return
и fail
.
Этот код компилируется без ошибок и предупреждений:
module P
where
newtype Parser a = Parser (String -> [(a, String)])
instance Monad Parser where
return a = Parser $ \inp -> [(a, inp)]
fail _ = Parser $ \_ -> []
Parser f >>= k = Parser $ \inp ->
[(b, inp'') | (a, inp') <- f inp, let Parser g = k a, (b, inp'') <- g inp']
item :: Parser Char
item = Parser $ \inp -> case inp of
[] -> []
(x:xs) -> [(x,xs)]
parse :: Parser a -> String -> [(a, String)]
parse (Parser p) inp = p inp
sat :: (Char -> Bool) -> Parser Char
sat p = do x <- item
if p x then return x else fail "predicate not satisfied"
На слайдах отсутствует реализация класса типов Монады
для типа Parser
.
С этим объявлением запись do
верна; x <- item
фактически выполняет правильную развёртку из [(Char, String)]
в (Char, String)
.
Кажется, я не могу получить это определение, не скомпилировав его, чтобы увидеть ошибку, но это начало:
instance Monad (Parser a) where
return x = pih_return x
-- (>>=) :: Parser a -> (a -> Parser b) -> Parser b
p >>= f = \inp -> case p inf of
[] -> []
(x:xs) -> (f x) xs -- this line is probably wrong
fail message = [] -- message is ignored