首先,让我们看一下没有记录语法的解析器 newtype:
newtype Parser' a = Parser' (String -> Maybe (a,String))
这个类型的作用应该很明显:它存储了一个函数String -> Maybe (a,String)。要运行这个解析器,我们需要创建一个新函数:
runParser' :: Parser' -> String -> Maybe (a,String)
runParser' (Parser' p) i = p i
现在我们可以运行像runParser' (Parser' $ \s -> Nothing) "my input" 这样的解析器了。
但现在请注意,由于 Haskell 函数是柯里化的,我们可以简单地删除对输入 i 的引用来获得:
runParser'' :: Parser' -> (String -> Maybe (a,String))
runParser'' (Parser' p) = p
这个函数完全等价于runParser',但是你可以换个思路:它不是显式地将解析器函数应用于值,而是简单地接受一个解析器并从中获取解析器函数;然而,由于柯里化,runParser'' 仍然可以与两个参数一起使用。
现在,让我们回到原来的类型:
newtype Parser a = Parser { parse :: String -> Maybe (a,String) }
您的类型和我的类型之间的唯一区别是您的类型使用record syntax,尽管可能有点难以识别,因为newtype 只能有一个字段;此记录语法自动定义一个函数parse :: Parser a -> (String -> Maybe (a,String)),它从Parser a 中提取String -> Maybe (a,String) 函数。希望其余的应该是显而易见的:由于柯里化,parse 可以使用两个参数而不是一个,这只是运行存储在Parser a 中的函数的效果。也就是说,你的定义完全等同于下面的代码:
newtype Parser a = Parser (String -> Maybe (a,String))
parse :: Parser a -> (String -> Maybe (a,String))
parse (Parser p) = p