Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/webpack/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell 为什么newtype语法创建函数_Haskell_Newtype - Fatal编程技术网

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”

    自动创建访问器函数的是记录语法。