何时评估我的Haskell表达式? [英] When is my Haskell expression evaluated?

查看:139
本文介绍了何时评估我的Haskell表达式?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果我定义

 λ>数据Bar = Bar Int导出Show 
λ>数据Foo = Foo Bar导出显示

 λ>让foo = tracefooFoo(tracebarbar 100)
λ> let two = tracetwo2
λ>让g(Foo x)y = y

然后我想我理解我为什么得到

 λ> g foo two 
foo
two
2

但如果我然后重复这一点,我得到

 λ> g foo two 
two
2

我不明白为什么<对于第二次调用 g 来说,code> foo 看起来没有被评估过,尤其是因为它显然不是已经可用,因为我可以验证

 λ> foo 
Foo bar
(Bar 100)

虽然 - 再一次对我混乱 - 重复前面给出的

 λ> foo 
Foo(Bar 100)

为什么我的 foo 表达式在某些情况下似乎已经被评估过,并且在其他情况下未被评估?那么为什么我的两个表达式总是需要被评估呢?

解决方案

这是由于两个的类型。让我们检查所有的类型到目前为止:

  ghci> :t foo 
foo :: Foo
ghci> :t two
two :: Num a => a



Aha! 两个是多态的。因此,它的行为取决于实际的 Num 实例。因此,需要在 g 中进行重新评估。我们可以使用:sprint 来检查:
$ b

  ghci> :sprint foo 
foo = Foo _ - 简化

这表明我们从未看过 Foo 的内容。 foo 位于弱首标范围。这回答你的第二个问题。但回到你的第一个。 会发生什么:sprint two

  ghci> :sprint two 
two = _

正如您所看到的,由于其多态特性, 两个不会到达WHNF。毕竟, WHNF应该采取哪种方式?您可能希望将它用作整数货币复合三重



顺便提一句,这是单态限制存在的原因,请参见Haskell的历史,第6.2节


6.2单形态限制



早期阶段争议的一个主要来源是所谓的称为
单态限制。假设 genericLength 具有
这个重载类型:

  genericLength` :: Num a => [b]  - > a 

现在考虑这个定义:

 f xs =(len,len)
其中
len = genericLength xs

它看起来应该只计算一次len,但实际上可以计算两次。为什么?因为我们可以推断出类型
len ::(Num a)=>一个;当使用字典 -
传递转换进行解析时, len 变成一个函数,对于每个 len ,其中每一个都可能用于不同的
类型。

另见本问答关于限制的更多信息


$ b $这就是说,如果我们修正两个的类型,我们可以很容易地改变这个:

  ghci的>让foo = tracefooFoo(跟踪barBar 100)
ghci> let two = tracetwo(2 :: Integer)
ghci>让g(Foo x)y = y

现在输出将与您预期的完全一致。或者,您可以启用:set -XMonomorphismRestriction 的单态限制,因为它在默认情况下在当前GHCi版本中被禁用:

  ghci的> :set -XMonomorphismRestriction 
ghci> let two = tracetwo2
ghci> :t two
two :: Integer - 由于违约规则


If I define

λ> data Bar = Bar Int deriving Show
λ> data Foo = Foo Bar deriving Show

and

λ> let foo = trace "foo" Foo (trace "bar" Bar 100)
λ> let two = trace "two" 2
λ> let g (Foo x)  y = y

then I think I understand why I get

λ> g foo two
foo
two
2

But if I then repeat this, I get

λ> g foo two
two
2

and I don't understand why foo appears not to have been evaluated for the second invocation of g, especially since it is clearly not (yet) somehow already available, as I can verify with

λ> foo
Foo bar
(Bar 100)

though — again, to my confusion — repeating the previous gives

λ> foo
Foo (Bar 100)

Why does my foo expression appear to be already evaluated in some cases, and not evaluated in others? And for that matter why does my two expression always need to be evaluated?

解决方案

That's due to two's type. Lets check all the type's so far:

ghci> :t foo
foo :: Foo
ghci> :t two
two :: Num a => a

Aha! two is polymorphic. Therefore, its behaviour depends on the actual Num instance. Therefore, it needs to get re-evaluated in g. We can check this by using :sprint:

ghci> :sprint foo
foo = Foo _             -- simplified

Which indicates that we never looked at the contents of Foo. foo is in weak head normal form. This answers your second question. But back to your first. What happens on :sprint two?

ghci> :sprint two
two = _

As you can see, due to its polymorphic nature, two doesn't get to WHNF. After all, which WHNF should it take? You might want to use it as Integer, or Currency, or Complex Triple.

This is, by the way, a reason for the existence of the monomorphism restriction, see "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.

See also this Q&A for more information about the restriction.

That being said, we can easily change this if we fix two's type:

ghci> let foo = trace "foo" Foo (trace "bar" Bar 100)
ghci> let two = trace "two" (2 :: Integer)
ghci> let g (Foo x)  y = y

Now the output will be exactly as you've expected. Alternatively, you can enable the monomorphism restriction with :set -XMonomorphismRestriction, as it is disabled in current GHCi versions by default:

ghci> :set -XMonomorphismRestriction
ghci> let two = trace "two" 2
ghci> :t two
two :: Integer -- due to defaulting rules

这篇关于何时评估我的Haskell表达式?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆