如何在 Haskell 中手动部分应用函数

How to manually partially apply a function in Haskell

我无法理解以下代码的工作原理。我正在尝试遵循找到的解析器示例 here。我之前使用过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

以下是我尝试手动 desugar/apply runParseritem 的方式:

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

这就是我卡住的地方。如果我用 Parser 中的函数替换 m,我会得到 parse parse s,这对我来说似乎是错误的。如何将 runParser 应用到 item 以便最终得到类型为 String -> Char 的函数?我觉得我的 attempt at desugaring 没电了。

编辑:我错误地指出 item 应用于 runParser;我在这里混淆了函数和变量。

也许这会让您朝着正确的方向开始:

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 ...)

我稍微修改了我的代码,它使用模式匹配而不是记录语法。这对其他人来说可能更容易理解:

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)]