从《 Haskell编程》(http://www.cs.nott.ac.uk/~gmh/book.html)一书中,解析器的定义如下:
> type Parser a = String -> [(a,String)]
但是,与示例代码(http://www.cs.nott.ac.uk/~gmh/Parsing.lhs)相比,定义有些不同。
> newtype Parser a = P (String -> [(a,String)])
我发现与以下页面的不同之处:https://wiki.haskell.org/Type#Type_and_newtype如下:
type引入类型的同义词,并使用相同的数据构造函数。 newtype引入了类型的重命名,并要求您提供新的构造函数。
这是我的问题:
对于新类型,为什么使用
P(...)
括住内容?它需要为新的构造函数提供newtype,但是我似乎没有从示例代码中找到一个。如何为newtype定义构造函数?不提供一个可以吗?
最佳答案
对于新类型,为什么使用P(...)
括住内容?
任何newtype
声明的类型都必须具有单个构造函数。在这种情况下,构造函数的名称为P
,其类型为
P :: (String -> [(a, String)]) -> Parser a
您还可以使用记录语法,因此它等效于
newtype Parser a = P { runParser :: String -> [(a, String)] }
或者,如果要使用
data
类型(在这种情况下,包装程序在运行时不会轻易优化),则将非常相似:data Parser a = P { runParser :: String -> [(a, String)] }
它需要为新的构造函数提供newtype,但是我似乎没有从示例代码中找到一个。如何为newtype定义构造函数?不提供一个可以吗?
如上所述,
newtype Parser
的构造函数命名为P
,并且newtype
必须完全有一个构造函数。需要进一步说明的是,
type
关键字构造了一个简单的别名。例如,String
被定义为type String = [Char]
您可以在采用
String
的任何函数中使用[Char]
,并且可以在采用[Char]
的任何函数中使用String
。由于FilePath
被定义为type FilePath = String
然后,您可以在任何使用
FilePath
的地方使用String
,因此可以在任何使用[Char]
的地方使用,反之亦然。这些只是用于简化更复杂类型的名称。我要说的是,实际上,除了非常简单的情况外,使用newtype
而不是type
更为常见,这仅仅是因为它允许类型系统在您的软件中强制执行更多操作。 type
还有一些缺点,因为您需要语言扩展才能在instance
声明中使用它们,并且必须始终将它们完全应用于其他表达式中。 newtype
的缺点是您必须包装很多/拆开它们,但是当使用真正复杂的程序时,这可能更有利。