mar*_*ngw 146 haskell types type-systems language-design
似乎newtype
定义只是data
遵循某些限制的定义(例如,只有一个构造函数),并且由于这些限制,运行时系统可以newtype
更有效地处理s.并且未定义值的模式匹配处理略有不同.
但是假设Haskell只知道data
定义,没有newtype
s:编译器不能自己发现给定的数据定义是否遵守这些限制,并自动更有效地对待它?
我确定我错过了什么,必须有更深层次的理由.
Nor*_*sey 179
两者newtype
和单构造函数都data
引入了单个值构造函数,但引入的值构造函数newtype
是strict,并且引入的值构造函数data
是惰性的.所以,如果你有
data D = D Int
newtype N = N Int
Run Code Online (Sandbox Code Playgroud)
然后N undefined
相当于undefined
并在评估时导致错误.但是,D undefined
是不是等同于undefined
,并且可以,只要你不要试图偷看里面评价.
编译器无法为自己处理此问题.
不,不是真的 - 这是程序员你可以决定构造函数是严格还是懒惰的情况.要了解何时以及如何使构造函数严格或懒惰,您必须比我更好地理解惰性求值.我坚持报告中的想法,即newtype
您可以重命名现有类型,例如有几种不同的不兼容测量类型:
newtype Feet = Feet Double
newtype Cm = Cm Double
Run Code Online (Sandbox Code Playgroud)
两者的行为与Double
运行时完全相同,但编译器承诺不会让您混淆它们.
Ros*_*one 61
根据了解你一个Haskell:
使用newtype关键字而不是data关键字.那为什么呢?好吧,一个,newtype更快.如果使用data关键字来包装类型,那么当程序运行时,所有包装和解包都会产生一些开销.但是如果你使用newtype,Haskell知道你只是用它来将现有的类型包装成一个新类型(因此就是名字),因为你希望它在内部是相同的但是有不同的类型.考虑到这一点,Haskell一旦解决了哪种类型的值,就可以摆脱包装和解包.
那么为什么不一直只使用newtype而不是数据呢?好吧,当您使用newtype关键字从现有类型创建新类型时,您只能拥有一个值构造函数,并且该值构造函数只能有一个字段.但是对于数据,您可以创建具有多个值构造函数的数据类型,并且每个构造函数可以包含零个或多个字段:
data Profession = Fighter | Archer | Accountant
data Race = Human | Elf | Orc | Goblin
data PlayerCharacter = PlayerCharacter Race Profession
Run Code Online (Sandbox Code Playgroud)
使用newtype时,您只能使用一个具有一个字段的构造函数.
现在考虑以下类型:
data CoolBool = CoolBool { getCoolBool :: Bool }
Run Code Online (Sandbox Code Playgroud)
这是使用data关键字定义的普通代数数据类型.它有一个值构造函数,它有一个类型为Bool的字段.让我们创建一个模式匹配CoolBool的函数,并返回值"hello",无论CoolBool中的Bool是True还是False:
helloMe :: CoolBool -> String
helloMe (CoolBool _) = "hello"
Run Code Online (Sandbox Code Playgroud)
而不是将此函数应用于普通的CoolBool,让我们抛出一个曲线球并将其应用于undefined!
ghci> helloMe undefined
"*** Exception: Prelude.undefined
Run Code Online (Sandbox Code Playgroud)
哎呀!一个例外!现在为什么会发生这种异常?使用data关键字定义的类型可以有多个值构造函数(即使CoolBool只有一个).因此,为了查看赋予函数的值是否符合(CoolBool _)模式,Haskell必须评估该值,以便在我们创建值时查看使用了哪个值构造函数.当我们尝试评估未定义的值时,即使是一点点,也会抛出异常.
不要使用CoolBool的data关键字,让我们尝试使用newtype:
newtype CoolBool = CoolBool { getCoolBool :: Bool }
Run Code Online (Sandbox Code Playgroud)
我们不必更改helloMe函数,因为如果使用newtype或data来定义类型,模式匹配语法是相同的.让我们在这里做同样的事情并将helloMe应用于未定义的值:
ghci> helloMe undefined
"hello"
Run Code Online (Sandbox Code Playgroud)
有效!嗯,为什么?好吧,正如我们所说,当我们使用newtype时,Haskell可以在内部以与原始值相同的方式表示新类型的值.它不必在它们周围添加另一个框,它只需要知道不同类型的值.并且因为Haskell知道使用newtype关键字创建的类型只能有一个构造函数,所以它不必评估传递给函数的值以确保它符合(CoolBool _)模式,因为newtype类型只能有一个可能的值构造函数和一个字段!
这种行为上的差异可能看起来微不足道,但它实际上非常重要,因为它帮助我们意识到即使用数据和新类型定义的类型从程序员的角度来看也类似,因为它们都有值构造函数和字段,它们实际上是两种不同的机制.虽然数据可用于从头开始创建自己的类型,但newtype用于从现有类型中创建一个全新的类型.对newtype值进行模式匹配并不像从盒子中取出一样(就像数据一样),它更多的是从一种类型到另一种类型的直接转换.
这是另一个来源.根据这篇Newtype文章:
newtype声明以与数据大致相同的方式创建新类型.newtypes的语法和用法实际上与数据声明的语法和用法相同 - 实际上,你可以用数据替换newtype关键字,它仍然可以编译,实际上你的程序很可能仍然有效.但是反过来却不正确 - 如果类型只有一个构造函数,其中只有一个字段,那么数据只能用newtype替换.
一些例子:
newtype Fd = Fd CInt
-- data Fd = Fd CInt would also be valid
-- newtypes can have deriving clauses just like normal types
newtype Identity a = Identity a
deriving (Eq, Ord, Read, Show)
-- record syntax is still allowed, but only for one field
newtype State s a = State { runState :: s -> (s, a) }
-- this is *not* allowed:
-- newtype Pair a b = Pair { pairFst :: a, pairSnd :: b }
-- but this is:
data Pair a b = Pair { pairFst :: a, pairSnd :: b }
-- and so is this:
newtype Pair' a b = Pair' (a, b)
Run Code Online (Sandbox Code Playgroud)
听起来很有限!那么为什么有人使用newtype?
短版本对一个具有一个字段的构造函数的限制意味着新类型和字段的类型直接对应:
Run Code Online (Sandbox Code Playgroud)State :: (s -> (a, s)) -> State s a runState :: State s a -> (s -> (a, s))
或者在数学术语中它们是同构的.这意味着在编译时检查类型之后,在运行时,两种类型可以基本上相同,没有通常与数据构造函数关联的开销或间接.因此,如果要为特定类型声明不同的类型类实例,或者想要使类型为抽象,则可以将其包装在newtype中,并且它将被视为与类型检查器不同,但在运行时相同.然后,您可以使用各种深度欺骗,如幻像或递归类型,而无需担心GHC改组字节数据无缘无故.
请参阅文章的杂乱位...
won*_*ice 49
痴迷于子弹列表的人的简单版本(未能找到一个,所以必须自己编写):
data - 使用值构造函数创建新的代数类型
newtype - 使用值构造函数创建新的"装饰"类型
type - 为类型创建替代名称(同义词)(如C中的typedef)
[*]关于模式匹配懒惰:
data DataBox a = DataBox Int
newtype NewtypeBox a = NewtypeBox Int
dataMatcher :: DataBox -> String
dataMatcher (DataBox _) = "data"
newtypeMatcher :: NewtypeBox -> String
newtypeMatcher (NewtypeBox _) = "newtype"
ghci> dataMatcher undefined
"*** Exception: Prelude.undefined
ghci> newtypeMatcher undefined
“newtype"
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
29217 次 |
最近记录: |