Haskell中type和newtype之间的区别

pro*_*eek 3 haskell types

从Haskell中的Programming(http://www.cs.nott.ac.uk/~gmh/book.html)一书中,解析器定义如下:

> type Parser a = String -> [(a,String)]
Run Code Online (Sandbox Code Playgroud)

但是,从示例代码(http://www.cs.nott.ac.uk/~gmh/Parsing.lhs)中,定义略有不同.

> newtype Parser a              =  P (String -> [(a,String)])
Run Code Online (Sandbox Code Playgroud)

我发现了这个页面的不同之处:https://wiki.haskell.org/Type#Type_and_newtype如下:

type引入了类型的同义词,并使用相同的数据构造函数.newtype引入了类型的重命名,并要求您提供新的构造函数.

这是我的问题:

  1. 对于新类型,为什么P(...)用于封装内容?
  2. 它需要为newtype提供新的构造函数,但我似乎没有从示例代码中找到一个.如何为newtype定义构造函数?可以不提供一个吗?

bhe*_*ilr 7

对于新类型,为什么P(...)用于封装内容?

任何newtype声明的类型都必须有一个构造函数.在这种情况下,构造函数被命名P,其类型是

P :: (String -> [(a, String)]) -> Parser a
Run Code Online (Sandbox Code Playgroud)

您也可以使用记录语法,因此它等同于

newtype Parser a = P { runParser :: String -> [(a, String)] }
Run Code Online (Sandbox Code Playgroud)

或者如果你要使用一个data类型(在这种情况下包装器不会在运行时很容易被优化掉),它将非常相似:

data Parser a = P { runParser :: String -> [(a, String)] }
Run Code Online (Sandbox Code Playgroud)

它需要为newtype提供新的构造函数,但我似乎没有从示例代码中找到一个.如何为newtype定义构造函数?可以不提供一个吗?

如上所述,newtype Parser命名的构造函数P,并且必须只有一个构造函数newtype.

更进一步说明,type关键字构造了一个简单的别名.例如,String定义为

type String = [Char]
Run Code Online (Sandbox Code Playgroud)

您可以String在任何需要的函数中使用[Char],并且可以[Char]在任何需要的函数中使用String.由于FilePath被定义为

type FilePath = String
Run Code Online (Sandbox Code Playgroud)

然后你就可以FilePath在任何你想使用的String地方使用它[Char],反之亦然.这些只是减少更复杂类型的名称.我会说在实践中使用newtype而不是type在非常简单的情况下更常见,仅仅因为它允许类型系统在您的软件中执行更多操作.types 也有缺点,因为你需要语言扩展才能在instance声明中使用它们,并且它们必须始终完全应用于其他表达式.缺点newtype是你必须对它们进行大量包装/解包,但在使用真正复杂的程序时,这可能更有利.