oro*_*ome 5 evaluation haskell lazy-evaluation
如果我定义
?> data Bar = Bar Int deriving Show
?> data Foo = Foo Bar deriving Show
Run Code Online (Sandbox Code Playgroud)
和
?> let foo = trace "foo" Foo (trace "bar" Bar 100)
?> let two = trace "two" 2
?> let g (Foo x) y = y
Run Code Online (Sandbox Code Playgroud)
然后我想我明白为什么会得到
?> g foo two
foo
two
2
Run Code Online (Sandbox Code Playgroud)
但是,如果我重复这一点,我会得到
?> g foo two
two
2
Run Code Online (Sandbox Code Playgroud)
我不明白为什么foo似乎没有被评估为第二次调用g,特别是因为它显然不是(尚)以某种方式已经可用,因为我可以验证
?> foo
Foo bar
(Bar 100)
Run Code Online (Sandbox Code Playgroud)
虽然 - 再次,我的困惑 - 重复前面给出
?> foo
Foo (Bar 100)
Run Code Online (Sandbox Code Playgroud)
为什么我的foo表达式在某些情况下似乎已经过评估,而在其他情况下却没有评估?那么为什么我的two表达总是需要被评估?
这是由于two类型.让我们检查目前为止的所有类型:
ghci> :t foo
foo :: Foo
ghci> :t two
two :: Num a => a
Run Code Online (Sandbox Code Playgroud)
啊哈!two是多态的.因此,它的行为取决于实际的Num实例.因此,需要重新评估g.我们可以通过以下方式检查:sprint:
ghci> :sprint foo
foo = Foo _ -- simplified
Run Code Online (Sandbox Code Playgroud)
这表明我们从未查看过的内容Foo.foo处于弱头正常状态.这回答了你的第二个问题.但回到你的第一个.会发生什么:sprint two?
ghci> :sprint two
two = _
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,由于其多态性,two无法获得WHNF.毕竟,这 WHNF应时间?您可能希望将其用作Integer,或Currency,或Complex Triple.
顺便说一下,这是存在单同性限制的原因,参见"Haskell的历史",第6.2节:
6.2单态限制
早期阶段争议的主要来源是所谓的"单态限制".假设
genericLength有这种重载类型:Run Code Online (Sandbox Code Playgroud)genericLength` :: Num a => [b] -> a现在考虑这个定义:
Run Code Online (Sandbox Code Playgroud)f xs = (len, len) where len = genericLength xs看起来len应该只计算一次,但它实际上可以计算两次.为什么?因为我们可以推断出类型
len :: (Num a) => a; 当与字典传递翻译相结合时,len成为每次出现时调用一次的函数,每个函数len可以在不同的类型中使用.
话虽这么说,如果我们修复two类型,我们可以很容易地改变它:
ghci> let foo = trace "foo" Foo (trace "bar" Bar 100)
ghci> let two = trace "two" (2 :: Integer)
ghci> let g (Foo x) y = y
Run Code Online (Sandbox Code Playgroud)
现在输出将完全按照您的预期.或者,您可以启用单态限制:set -XMonomorphismRestriction,因为默认情况下在当前GHCi版本中禁用它:
ghci> :set -XMonomorphismRestriction
ghci> let two = trace "two" 2
ghci> :t two
two :: Integer -- due to defaulting rules
Run Code Online (Sandbox Code Playgroud)
> :t foo
foo :: Foo
> :t two
two :: Num a => a
Run Code Online (Sandbox Code Playgroud)
第二个是多态的,所以它是伪装的功能!每次使用它时,您都会评估一个新的trace呼叫.
| 归档时间: |
|
| 查看次数: |
115 次 |
| 最近记录: |