【问题标题】:`Ord a =>` or `Num a =>``Ord a =>` 或 `Num a =>`
【发布时间】:2011-06-12 13:35:22
【问题描述】:

我有以下功能:

which (x:xs) = worker x xs
worker x [] = x
worker x (y:ys)
    | x > y      = worker y ys
    | otherwise  = worker x ys

我想知道我应该如何定义上述函数whichworker的类型签名?

例如,以下哪种方式最适合作为工人的类型签名

worker :: Num a => a -> [a] -> a,

worker :: Ord a => a -> [a] -> a?

我真的很困惑,不知道我应该选择哪三个。我很感激你的想法。谢谢。

【问题讨论】:

  • 你的实际功能是什么for?是为了数字吗?整数?有什么可以订购的吗?
  • @Gabe 输出是一个数字(即FloatInt),因此上面有> 符号。现在我只是不确定应该是Ord a =>... 还是Num a =>... 真的很困惑!不过感谢您的提问,帮助我从列表中删除了第三个 :-)
  • @maclunian:您可以在任何有顺序的东西上使用>,而不仅仅是数字。这就是为什么首先使用 Ord 而不是 Num 起作用的原因。
  • 只是Num 不起作用,因为并非所有数字都有顺序,例如复数。
  • 出于兴趣,你为什么不用前奏曲中的minimum

标签: list function haskell types type-signature


【解决方案1】:

如果您在没有显式类型签名的情况下定义函数,Haskell 将推断出最通用的函数。如果您不确定,这是弄清楚您的定义将如何被阅读的最简单方法;然后,您可以将其复制到您的源代码中。一个常见的错误是错误地键入一个函数,然后在其他地方得到一个令人困惑的类型错误。

无论如何,您可以通过在 ghci 中输入 :i Num 或阅读文档来获取有关 Num 类的信息。 Num 类为您提供+*-negateabssignumfromInteger,以及@9876543@31@ 和@98765432 的每个功能。请注意,<> 不存在!要求 Num 的值并尝试比较它们实际上会产生类型错误——并非每种数字都可以比较。

所以应该是Ord a => ...,因为如果你尝试Num a => ...会产生类型错误。

【讨论】:

  • 想一想,你不能用worker :: a -> [a] -> a吗?
  • 你不能。既然你有x > y这个表达式,它就会抱怨No instance for (Ord a)
【解决方案2】:

如果您考虑一下您的函数的作用,您会发现which xs 返回xs 中的最小值。什么可以有最小值? Orderable 的东西列表!

【讨论】:

    【解决方案3】:

    询问 ghci,看看它说了什么。我只是将您的代码原样复制粘贴到一个文件中并将其加载到 ghci 中。然后我使用了:t,这是一个特殊的 ghci 命令来确定某物的类型。

    ghci> :t which
    which :: (Ord t) => [t] -> t
    ghci> :t worker
    worker :: (Ord a) => a -> [a] -> a
    

    Haskell 的类型推断在大多数情况下都非常聪明。学会相信它。其他答案充分涵盖了为什么在这种情况下应该使用Ord;我只是想确保明确提到 ghci 作为一种确定事物类型的技术。

    【讨论】:

      【解决方案4】:

      我总是使用 Ord 类型约束。它是最通用的,因此可以更频繁地重复使用。

      使用 Num 而不是 Ord 没有任何优势。

      Int 可能有一个小的优势,因为它不是多态的并且不需要字典查找。如果我需要性能,我仍然会使用 Ord 并使用specialize pragma。

      【讨论】:

      • 想一想,你不能用worker :: a -> [a] -> a吗?
      • 不,(>) 是 Ord 类型类的一部分。没有约束就没有定义
      【解决方案5】:

      编辑:在 cmets 之后改变了我的答案。

      这取决于您想要比较的内容。如果您希望能够比较DoubleFloatIntIntegerChar,请使用Ord。如果您只想比较Int,那么只需使用Int

      如果您还有类似的问题,只需查看类型类的实例,以了解您希望能够在函数中使用哪些类型。

      【讨论】:

      • 想一想,你不能用worker :: a -> [a] -> a吗?
      • 是的,你可以。但是您应该尽可能多地使用类型声明的力量,因为编译器会捕获与类型相关的错误。这是一个很好的解释:book.realworldhaskell.org/read/…
      • @augustss 当您只是投反对票并说它不起作用时,没有人会学到任何东西。所以请告诉我们为什么它不起作用,以便我和其他人可以从这个错误中吸取教训。我猜你指的是 Num 不包含 OPs 问题中指定的比较函数?
      • 至少有两个人在@augustss 发表评论前几个小时解释了为什么Num 不起作用。更不用说,如果您查看您自己链接到的 Num 的文档,就会立即发现这一点(顺便说一下,这些页面已经过时,无论如何都不应该作为参考给出)。
      • 即使很难,如果您提示问题所在并使用更友好的方法,对每个人都会更有帮助。写评论可能会多花 10 秒钟,但它会让社区受益匪浅。与其一直用这种心态来证明人们是错的,不如尝试以更积极的方式教人们呢? :)
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-05-01
      • 1970-01-01
      • 2021-11-19
      • 1970-01-01
      • 2011-04-14
      • 2019-08-13
      • 2011-01-22
      相关资源
      最近更新 更多