【问题标题】:Why did pointfree.io choose liftM2 instead of liftA2?为什么 pointfree.io 选择 liftM2 而不是 liftA2?
【发布时间】:2018-03-29 20:43:03
【问题描述】:

我最近在ExercismISBN Verifier 练习编写了一个解决方案,当我通过pointfree.io 运行这个函数时:

\c -> isDigit c || c == 'X'

我回来了:

liftM2 (||) isDigit ('X' ==)

为什么pointfree.io从Control.Monad选择liftM2而不是从Control.Applicative选择liftA2

【问题讨论】:

  • pointfree.io 是一个有趣的玩具,仅此而已。它不应该以任何方式给出好的建议,它只是暗示什么是可能的。
  • 我很惊讶它选择了('X' ==) 而不是(== 'X')。显然这种转置是“安全的”,因为(==) 应该是对称的,但为什么不直接选择精确的转换呢?
  • @amalloy 我无法回答为什么该工具会这样做,但这是我在编写部分应用程序时会注意的事情。根据经验,首先应用较早的参数会更好,因为精心编写的函数在给定第一个参数时可能会比在 lambda 下使用时共享更多的计算。例如想象一下,如果(==) 首先比较每个参数的一些昂贵的统计数据,然后继续进行其他一些比较;那么map (foo==) bar 可能比map (==foo) bar 更有效,因为前者只计算了一次foo 的统计数据。

标签: haskell monads functor applicative


【解决方案1】:

事实上,Control.MonadControl.Applicative 早很多。

Monads 已经在 Haskell 98 中,而关于应用函子的论文是在 2007 年引入的。Hackage 中的包自 2005 年以来就存在。

Wikipedia:

由于历史意外,应用函子没有实现为 Monad 的超类,而是作为一个单独的类型类。事实证明,在实践中,这种分离的需求很少,因此在 2014 年,有人提出追溯性地使 Applicative 成为 Monad 的超类。

所以liftM{N} 仍然有效。

【讨论】:

  • 这个答案是完全正确的。或许值得注意的是,维基百科的解释相当奇怪:“对这种分离的需求很少”听起来像是一种委婉说法,因为分离没有任何目的。
  • @duplode,我认为这个解释听起来不对,因为Applicative 一直(据我所知)是Functor 的子类。这肯定是 base-4.0.0.0,早在 2009 年。
  • @dfeuer 哦,哇,这确实是完全错误的。 (我实际上并没有意识到该页面也在谈论 Functor,因为深夜发帖和期待看到关于 AMP 的常见评论。)
  • @duplode,在检查了所有古老的文档以验证 Applicative 自从 base-4.0.0.0 引入以来一直是 Functor 的子类后,我编辑了 Wikipedia 以消除非常明确的错误。我想有人看到原始论文中延伸的Applicative 类缺少Functor 超类并感到困惑。
  • @dfeuer 这段对话让我想起了那篇文章的第一has also been recognised as nonsense for quite a while。我已经做了一个快速的尝试,如果没有别的,那就是正确的。
猜你喜欢
  • 2012-10-24
  • 1970-01-01
  • 1970-01-01
  • 2014-08-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多