Haskell 为什么newtype语法创建函数
我看一下这个宣言:Haskell 为什么newtype语法创建函数,haskell,newtype,Haskell,Newtype,我看一下这个宣言: newtype Parser a = Parser { parse :: String -> Maybe (a,String) } 以下是我的理解: 1) 解析器被声明为具有类型参数a 2) 您可以通过提供解析器函数来实例化解析器,例如p=Parser(\s->Nothing) 我观察到的是,突然我定义了一个函数名parse,它能够运行解析器 例如,我可以运行: parse (Parser (\s -> Nothing)) "my input" 并获取无作
newtype Parser a = Parser { parse :: String -> Maybe (a,String) }
以下是我的理解:
1) 解析器被声明为具有类型参数a
2) 您可以通过提供解析器函数来实例化解析器,例如p=Parser(\s->Nothing)
我观察到的是,突然我定义了一个函数名parse
,它能够运行解析器
例如,我可以运行:
parse (Parser (\s -> Nothing)) "my input"
并获取无
作为输出
这个解析函数是如何用这个特定的签名定义的?这个函数如何“知道”执行给定给它的解析器?希望有人能消除我的困惑
谢谢 首先,让我们看一看没有记录语法的解析器newtype:
newtype解析器'a=Parser'(String->Maybe(a,String))
这种类型的作用应该很明显:它存储一个函数String->Maybe(a,String)
。要运行此解析器,我们需要创建一个新函数:
runParser'::Parser'->String->Maybe(a,String)
runParser'(Parser'p)i=pi
现在我们可以运行解析器,比如runParser'(解析器'$\s->Nothing)“我的输入”
但现在请注意,由于Haskell函数是curry函数,我们只需删除对输入i
的引用即可获得:
runParser'::Parser'->(String->Maybe(a,String))
运行语法分析器“”(语法分析器“p)=p
此函数与runParser'
完全等效,但您可以换一种方式来考虑:它不必显式地将解析器函数应用于值,只需获取解析器并从中获取解析器函数;但是,由于使用curry,runParser'
仍然可以与两个参数一起使用
现在,让我们回到原始类型:
newtype Parser a=Parser{parse::String->Maybe(a,String)}
你的类型和我的类型之间唯一的区别是你的类型使用了,尽管可能有点难以识别,因为newtype
只能有一个字段;此记录语法自动定义一个函数parse::Parser a->(String->Maybe(a,String))
,该函数从解析器a
中提取String->Maybe(a,String)
函数。希望剩下的应该是显而易见的:多亏了currying,parse
可以与两个参数而不是一个参数一起使用,这只会产生运行解析器a
中存储的函数的效果。换句话说,您的定义完全等同于以下代码:
newtype Parser a=Parser(String->Maybe(a,String))
parse::Parser a->(String->Maybe(a,String))
解析(解析器p)=p
当您编写newtype Parser a=Parser{parse::String->Maybe(a,String)}
时,您将介绍三件事:
Parser
的类型Parser
的Parser
的术语级构造函数。此函数的类型为Parser::(String->Maybe(a,String))->Parser a
您给它一个函数,它将它包装在解析器中
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) }
这表明unpasse
删除了解析函数周围的包装。但是,我建议在使用newtypes
时,您的类型和构造函数具有相同的名称
这个函数如何“知道”执行给定给它的解析器
您正在使用parse
解包函数,然后使用调用解包函数“myInput”
自动创建访问器函数的是记录语法。