我的 Haskell 表达式何时被求值?

2024-01-11

如果我定义

λ> 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

然后我想我明白为什么我得到

λ> 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需要评估吗?


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

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

Aha! two是多态的。因此,它的行为取决于actual Num实例。因此,需要重新评估g。我们可以通过使用来检查这一点:sprint:

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

这表明我们从未查看过内容Foo. foo is in 弱头正常形态 https://wiki.haskell.org/Weak_head_normal_form。这回答了你的第二个问题。但回到你的第一个。发生了什么:sprint two?

ghci> :sprint two
two = _

正如你所看到的,由于其多态性,two没有到达 WHNF。毕竟,which需要什么时间?你可能想用它作为Integer, or Currency, or Complex Triple.

顺便说一句,这是单态限制存在的原因,请参阅“Haskell 的历史”,第 6.2 节 http://research.microsoft.com/en-us/um/people/simonpj/papers/history-of-haskell/history.pdf:

6.2 单态限制

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

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

现在考虑这个定义:

f xs = (len, len)
  where
    len = genericLength xs

看起来 len 应该只计算一次,但实际上可以计算两次。为什么?因为我们可以推断类型len :: (Num a) => a;当用字典脱糖时- 通过翻译,len成为一个被调用一次的函数 对于每次出现len,其中每一个都可能在不同的地方使用 类型。

也可以看看有关限制的更多信息,请参阅此问答 https://stackoverflow.com/questions/32496864/what-is-the-monomorphism-restriction.

话虽这么说,如果我们修复的话,我们可以很容易地改变它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

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

ghci> :set -XMonomorphismRestriction
ghci> let two = trace "two" 2
ghci> :t two
two :: Integer -- due to defaulting rules
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

我的 Haskell 表达式何时被求值? 的相关文章

  • 整数转浮点数

    这段代码的工作原理 posToXY Float gt Float gt Integer posToXY a b do let y a b round y 但这不起作用 posToXY Integer gt Integer gt Intege
  • 类 GADT 类型变量的未来角色?

    A 昨天的问题 https stackoverflow com q 41135212 3072788有一个定义HList 来自HList https hackage haskell org package HList 0 4 1 0 doc
  • Haskell Cabal 包 - 找不到 Paths_ 模块

    我正在开发一个 Haskell 项目 Happstack 服务器 Blaze HTML 前端作为主要库 我想添加一个静态数据目录 看起来你可以使用 Cabal 使用自动生成的Path
  • Haskell 中的实例声明

    我有这两个功能 primes sieve 2 where sieve p xs p sieve x x lt xs x mod p gt 0 isPrime number number 1 null x x lt takeWhile x g
  • 在 Haskell 中增长数组

    我想在 Haskell 中实现以下 命令式 算法 给定一个序列对 e0 s0 e1 s1 e2 s2 en sn 其中 e 和 s 部分不一定是自然数不同的是 在每个时间步都会随机选择该序列的一个元素 例如 ei si 并根据 ei si
  • 持久 selectList 导致错误“无法将类型‘BaseBackend backend0’与‘SqlBackend’匹配”

    我遇到以下编译错误 Couldn t match type BaseBackend backend0 with SqlBackend arising from a use of runSqlite The type variable bac
  • Haskell 中的 print 是纯函数吗?

    Is print在 Haskell 中是纯函数 为什么或者为什么不 我认为不是 因为它并不总是返回与纯函数应返回的值相同的值 类型的值IO Int并不是真正的Int 它更像是一张纸 上面写着 嘿 Haskell 运行时 请生成一个Int如此
  • Haskell:是的,没有类型类。为什么是整数?

    我有一个关于 GHCi 如何假定整数类型的问题 我正在阅读 Learn you a Haskell 是 否类型的课程 如果您想阅读全文 这里有一个链接 http learnyouahaskell com making our own typ
  • 纯函数怎么能做IO呢?

    我最近了解到莫纳德随机数 http hackage haskell org package MonadRandom 0 1 13 docs Control Monad Random Class html t 3aMonadRandom图书馆
  • 将 num 的签名键入 double?

    我才刚刚开始为你学习 Haskell 以获得伟大的好处 并且我在类型类方面遇到了一些麻烦 我想创建一个接受任何数字类型并强制其为双精度的函数 我的第一个想法是定义 numToDouble Num gt Double 但我认为这不起作用 因为
  • Haskell 中的分类结构

    Hask通常被认为是一个范畴 其对象是类型 态射是函数 然而 我看到 Conor McBride pigworker 警告不要使用Hask多次 1 https stackoverflow com a 45905082 474311 2 ht
  • 使用 FoldLine 解析多个块

    对于这个简化的问题 我试图解析一个如下所示的输入 foo bar baz quux woo hoo xyzzy glulx into foo bar baz quux woo hoo xyzzy glulx 我尝试过的代码如下 import
  • Haskell 中的中缀运算符优先级

    对于以下 Haskell 表达式 返回 a gt gt f 应该读作 返回a gt gt f or 返回 a gt gt f 这里的相关规则是什么 规则始终是函数应用程序的优先级高于任何运算符 因此 return a gt gt f 被解析
  • 简单 Haskell Monad - 随机数

    我正在尝试扩展代码这个帖子 https stackoverflow com questions 3944170 haskell and state 接受的答案 允许我能够基于以种子作为参数的函数 randomGen 调用 randomGen
  • QuickCheck是否可以生成任意函数

    我试图为身份编写一个 QuickCheck 测试 f y f y 我最初的计划是编写一个返回函数和整数的任意生成器 具有签名Gen Int gt Int Int 并在prop DollerDoesNothing使用 不使用测试该功能应用程序
  • Haskell 对于 Web 应用程序来说足够成熟吗? [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • Data.Sequence 中的 inits 和 tails 如何工作?

    Louis Wasserman 编写了当前的实现inits and tails in Data Sequence 他表示它们非常高效 事实上 只要查看代码 我就可以看到 无论它们在做什么 它们都是以干净 自上而下的方式进行的 这往往会给惰性
  • 管道:多个流消费者

    我编写了一个程序来计算语料库中 NGram 的频率 我已经有一个函数 它消耗一串令牌并生成一个订单的 NGram ngram Monad m gt Int gt Conduit t m t trigrams ngram 3 countFre
  • Haskell Data.Decimal 作为 Aeson 类型

    是否可以解析一个数据 十进制 https hackage haskell org package Decimal 0 4 2 docs Data Decimal html使用 Aeson 包从 JSON 获取 假设我有以下 JSON foo
  • C++ 概念与 Haskell 类型类有何不同?

    Concepts TS 中的 C 概念最近已合并到 GCC 主干中 概念允许人们通过要求类型满足概念的条件 例如 可比较 来约束通用代码 Haskell 有类型类 我对 Haskell 不太熟悉 概念和类型类如何相关 概念 由概念 TS 定

随机推荐