我看看这个声明:
newtype Parser a = Parser { parse :: String -> Maybe (a,String) }
以下是我的理解:
1( Parser被声明为具有类型参数a
的类型
2( 您可以通过提供解析器函数来实例化Parser,例如p = Parser (s -> Nothing)
我观察到的是,我突然定义了一个函数名parse
,它能够运行Parser。
例如,我可以运行:
parse (Parser (s -> Nothing)) "my input"
并得到CCD_ 4作为输出。
这个解析函数是如何用这个特定的签名定义的?这个函数是如何"知道"执行给它的Parser的?希望有人能澄清我的困惑。
谢谢!
当您编写newtype Parser a = Parser { parse :: String -> Maybe (a,String) }
时,您将介绍三件事:
-
一个名为
Parser
的类型。 -
Parser
的一个术语级构造函数名为Parser
。此功能的类型为
Parser :: (String -> Maybe (a, String)) -> Parser a
你给它一个函数,它将它封装在Parser
中
- 一个名为
parse
的函数,用于删除Parser
包装并取回您的函数。此函数的类型为:
parse :: Parser a -> String -> Maybe (a, String)
在ghci
:中检查自己
Prelude> newtype Parser a = Parser { parse :: String -> Maybe (a,String) }
Prelude> :t Parser
Parser :: (String -> Maybe (a, String)) -> Parser a
Prelude> :t parse
parse :: Parser a -> String -> Maybe (a, String)
Prelude>
毫无意义的是,术语级构造函数(Parser
(和移除包装器的函数(parse
(都是任意名称,不需要与类型名称匹配。例如,写是很常见的
newtype Parser a = Parser { unParser :: String -> Maybe (a,String) }
这清楚地表明CCD_ 15删除了解析函数的包装。但是,我建议您的类型和构造函数在使用newtypes
时使用相同的名称。
这个函数如何"知道"执行给它的解析器
使用parse
展开函数,然后使用"myInput"
调用展开的函数。
首先,让我们看看一个没有记录语法的解析器newtype:
newtype Parser' a = Parser' (String -> Maybe (a,String))
这种类型的作用应该很明显:它存储一个函数String -> Maybe (a,String)
。要运行这个解析器,我们需要创建一个新函数:
runParser' :: Parser' a -> String -> Maybe (a,String)
runParser' (Parser' p) i = p i
现在我们可以运行像runParser' (Parser' $ s -> Nothing) "my input"
这样的解析器了。
但现在请注意,由于Haskell函数是curry函数,我们可以简单地删除对输入i
的引用以获得:
runParser'' :: Parser' a -> (String -> Maybe (a,String))
runParser'' (Parser' p) = p
这个函数完全等同于runParser'
,但您可以用不同的方式来看待它:它不将解析器函数显式地应用于值,而是简单地获取一个解析器并从中获取解析器函数;然而,由于currying,runParser''
仍然可以与两个参数一起使用。
现在,让我们回到您的原始类型:
newtype Parser a = Parser { parse :: String -> Maybe (a,String) }
您的类型和我的类型之间的唯一区别是,您的类型使用记录语法,尽管这可能有点难以识别,因为newtype
只能有一个字段;该记录语法自动定义从Parser a
中提取String -> Maybe (a,String)
函数的函数parse :: Parser a -> (String -> Maybe (a,String))
。希望其余部分应该是显而易见的:由于currying,parse
可以与两个参数一起使用,而不是一个参数,这只会产生运行存储在Parser a
中的函数的效果。换句话说,您的定义完全等同于以下代码:
newtype Parser a = Parser (String -> Maybe (a,String))
parse :: Parser a -> (String -> Maybe (a,String))
parse (Parser p) = p