Как вручную частично применить функцию в Haskell - PullRequest
0 голосов
/ 22 декабря 2018

Мне трудно понять, как работает следующий код.Я пытаюсь следовать найденному примеру парсера здесь .Я использовал ReadP раньше и хочу получить более глубокое понимание того, как работают парсеры.Мой вопрос не относится к парсерам, а скорее к тому, как работает функциональное приложение в Haskell.Вот код:

module NanoParsec where

import Data.Char
import Control.Monad
import Control.Applicative

newtype Parser a = Parser { parse :: String -> [(a,String)] }

runParser :: Parser a -> String -> a
runParser m s =
    case parse m s of
        [(res, [])] -> res
        [(_, rs)]   -> error "Parser did not consume entire stream."
        _           -> error "Parser error."

item :: Parser Char
item = Parser $ \s ->
    case s of
        []     -> []
        (c:cs) -> [(c,cs)]

Я понимаю, что импорт пока не нужен.Когда я загружаю это в ghci, оно работает как положено:

Prelude> runParser item "m"
'm'
Prelude> runParser item "ms"
*** Exception: Parser did not consume entire stream.

Так что здесь нет ничего удивительного.У меня проблемы с тем, чтобы обернуть голову, как runParser применяется к item.Частичное применение runParser к item дает функцию типа String -> Char:

Parser> :t runParser item
runParser item :: String -> Char

Вот как я пытаюсь десагар / применить runParser к item вручную:

runParser item 
runParser Parser (\s -> ...)
(\m -> \s -> case parse m s of ...) Parser (\s -> ...)

Вот где я застрял.Если я заменю m на функцию в Parser, я получу parse parse s, что мне кажется неправильным.Как мне применить runParser к item, чтобы я получил функцию типа String -> Char?Я чувствую, что моя попытка обесценивания выключена.

РЕДАКТИРОВАТЬ : я ошибочно заявил, что item применяется к runParser;Я перепутал функцию и переменную здесь.

Ответы [ 2 ]

0 голосов
/ 22 декабря 2018

Я немного изменил свой код, он использует сопоставление с образцом вместо синтаксиса записи.Это может быть легче понять для других:

module NanoParsec where

import Data.Char
import Control.Monad
import Control.Applicative

-- newtype Parser a = Parser { parse :: String -> [(a,String)] }
newtype Parser a = Parser (String -> [(a,String)])

runParser :: Parser a -> String -> a
runParser (Parser p) s =
    case p s of
        [(res, [])] -> res
        [(_, rs)]   -> error "Parser did not consume entire stream."
        _           -> error "Parser error."

item :: Parser Char
item = Parser $ \s ->
    case s of
        []     -> []
        (c:cs) -> [(c,cs)]
0 голосов
/ 22 декабря 2018

Возможно, это поможет вам начать в правильном направлении:

runParser item
= { definition of item }
runParser (Parser $ \s -> case s of ...)
= { definition of runParser }
(\m s -> case parse m s of ...) (Parser $ \s -> case s of ...)
= { substitute argument for m everywhere }
(\s -> case parse (Parser $ \s -> case s of ...) s of ...)
= { definition of parse }
(\s -> case (\(Parser f) -> f) (Parser $ \s -> case s of ...) s of ...)
= { substitute argument for f everywhere }
(\s -> case (\s -> case s of ...) s of ...)
= { substitute argument for s everywhere }
(\s -> case (case s of ...) of ...)
...