我的 Haskell 表达式何时被评估?
When is my Haskell expression evaluated?
如果我定义
λ> data Bar = Bar Int deriving Show
λ> data Foo = Foo Bar deriving Show
和
λ> let foo = trace "foo" Foo (trace "bar" Bar 100)
λ> let two = trace "two" 2
λ> let g (Foo x) y = y
然后我想我明白为什么我得到
λ> g foo two
foo
two
2
但是如果我再重复这个,我会得到
λ> g foo two
two
2
而且我不明白为什么 foo
似乎没有针对 g
的第二次调用进行评估,特别是因为它显然(还)不知何故已经可用,而我可以用
验证
λ> foo
Foo bar
(Bar 100)
虽然——再次让我感到困惑——重复前面的给出
λ> foo
Foo (Bar 100)
为什么我的 foo
表达式在某些情况下似乎已经求值,而在其他情况下却没有求值?就此而言,为什么我的 two
表达式 always 需要被评估?
> :t foo
foo :: Foo
> :t two
two :: Num a => a
第二个是多态,所以它是变相的函数!每次使用它时,您都会评估一个新的 trace
调用。
那是因为 two
的类型。让我们检查到目前为止的所有类型:
ghci> :t foo
foo :: Foo
ghci> :t two
two :: Num a => a
啊哈! two
是多态的。因此,它的行为取决于实际Num
实例。因此,它需要在 g
中重新评估。我们可以使用 :sprint
:
进行检查
ghci> :sprint foo
foo = Foo _ -- simplified
这表明我们从未看过Foo
的内容。 foo
在 weak head normal form 中。这回答了你的第二个问题。但回到你的第一个。 :sprint two
会发生什么?
ghci> :sprint two
two = _
如您所见,由于其多态性,two
无法进入 WHNF。毕竟,which WHNF 应该拿吗?您可能希望将其用作 Integer
、Currency
或 Complex Triple
.
顺便说一下,这是存在单态限制的原因,参见"A History of Haskell", section 6.2:
6.2 The monomorphism restriction
A major source of controversy in the early stages was the so-called
“monomorphism restriction.” Suppose that genericLength
has
this overloaded type:
genericLength` :: Num a => [b] -> a
Now consider this definition:
f xs = (len, len)
where
len = genericLength xs
It looks as if len should be computed only once, but it can actually be computed twice. Why? Because we can infer the type
len :: (Num a) => a
; when desugared with the dictionary-
passing translation, len
becomes a function that is called once
for each occurrence of len
, each of which might used at a different
type.
另见 。
也就是说,如果我们修复 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
现在输出将完全符合您的预期。或者,您可以使用 :set -XMonomorphismRestriction
启用单态限制,因为它在当前 GHCi 版本中默认禁用:
ghci> :set -XMonomorphismRestriction
ghci> let two = trace "two" 2
ghci> :t two
two :: Integer -- due to defaulting rules
如果我定义
λ> data Bar = Bar Int deriving Show
λ> data Foo = Foo Bar deriving Show
和
λ> let foo = trace "foo" Foo (trace "bar" Bar 100)
λ> let two = trace "two" 2
λ> let g (Foo x) y = y
然后我想我明白为什么我得到
λ> g foo two
foo
two
2
但是如果我再重复这个,我会得到
λ> g foo two
two
2
而且我不明白为什么 foo
似乎没有针对 g
的第二次调用进行评估,特别是因为它显然(还)不知何故已经可用,而我可以用
λ> foo
Foo bar
(Bar 100)
虽然——再次让我感到困惑——重复前面的给出
λ> foo
Foo (Bar 100)
为什么我的 foo
表达式在某些情况下似乎已经求值,而在其他情况下却没有求值?就此而言,为什么我的 two
表达式 always 需要被评估?
> :t foo
foo :: Foo
> :t two
two :: Num a => a
第二个是多态,所以它是变相的函数!每次使用它时,您都会评估一个新的 trace
调用。
那是因为 two
的类型。让我们检查到目前为止的所有类型:
ghci> :t foo
foo :: Foo
ghci> :t two
two :: Num a => a
啊哈! two
是多态的。因此,它的行为取决于实际Num
实例。因此,它需要在 g
中重新评估。我们可以使用 :sprint
:
ghci> :sprint foo
foo = Foo _ -- simplified
这表明我们从未看过Foo
的内容。 foo
在 weak head normal form 中。这回答了你的第二个问题。但回到你的第一个。 :sprint two
会发生什么?
ghci> :sprint two
two = _
如您所见,由于其多态性,two
无法进入 WHNF。毕竟,which WHNF 应该拿吗?您可能希望将其用作 Integer
、Currency
或 Complex Triple
.
顺便说一下,这是存在单态限制的原因,参见"A History of Haskell", section 6.2:
6.2 The monomorphism restriction
A major source of controversy in the early stages was the so-called “monomorphism restriction.” Suppose that
genericLength
has this overloaded type:genericLength` :: Num a => [b] -> a
Now consider this definition:
f xs = (len, len) where len = genericLength xs
It looks as if len should be computed only once, but it can actually be computed twice. Why? Because we can infer the type
len :: (Num a) => a
; when desugared with the dictionary- passing translation,len
becomes a function that is called once for each occurrence oflen
, each of which might used at a different type.
另见
也就是说,如果我们修复 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
现在输出将完全符合您的预期。或者,您可以使用 :set -XMonomorphismRestriction
启用单态限制,因为它在当前 GHCi 版本中默认禁用:
ghci> :set -XMonomorphismRestriction
ghci> let two = trace "two" 2
ghci> :t two
two :: Integer -- due to defaulting rules