【发布时间】:2010-10-27 07:41:20
【问题描述】:
经常有人想在产品数据类型上实现<=>(比较,或“宇宙飞船”)运算符,即具有多个字段的类(所有这些(我们希望!)已经有<=>已实现),按一定顺序比较字段。
def <=>(o)
f1 < o.f1 && (return -1)
f1 > o.f1 && (return 1)
f2 < o.f2 && (return -1)
f2 > o.f2 && (return 1)
return 0
end
这既乏味又容易出错,尤其是在有很多字段的情况下。它很容易出错,以至于我经常觉得我应该对该函数进行单元测试,这只会增加乏味和冗长。
Haskell 提供了一种特别好的方法:
导入 Data.Monoid (mappend) 导入 Data.Ord(比较) -- 来自标准库: -- 数据排序 = LT |情商 |燃气轮机 数据 D = D { f3 :: Int, f2 :: Double, f1 :: Char } 推导 Show compareD :: D -> D -> 排序 compareD = foldl1 mappend [比较 f1,比较 f2,比较 f3](对于不熟悉fold的人,以上扩展为
comparing f1 `mappend` comparing f2 `mappend` comparing f3
它产生一个函数,可以应用于两个Ds,产生一个Ordering。)
compareD 的定义非常简单,显然是正确的,即使没有静态类型检查,我也不觉得需要对其进行单元测试。
实际上,这个问题可能比这个更有趣,因为我可能不想只使用标准的<=> 运算符,而是在不同的时间以不同的方式排序,例如:
所以,问题:
- 在 Ruby 中实现这类事情的典型方式是什么?
- 仅使用标准库中定义的内容最好的方法是什么?
- 相比之下,与上面的 Haskell 代码有多接近,它的可靠性如何?如有必要,如何确保字段具有正确实现的
<=>或<和>运算符?
顺便说一句,虽然这是一个 Ruby 问题,但如果本网站的长辈们同意,我很高兴考虑讨论有关 Haskell 技术的主题。请随时评论这是否合适,如果合适,请将此帖子标记为“haskell”。
【问题讨论】:
标签: ruby combinators spaceship-operator