4

我正在尝试实现一个简单的 min 函数,该函数接受两个参数&如果第一个必须按排序顺序出现在第二个之前,则返回 True,否则返回 False:

min :: a -> a -> Bool
min a b = if a < b then True else False

我得到:

No instance for (Ord a)
arising from a use of `<'
4

3 回答 3

25

如果您查看文档,您将看到 for 的类型(<)

(<) :: a -> a -> Bool

这是误导!

类型声明出现在类型类定义中:

class Eq a => Ord a where ...

所以完整的类型是

(<) :: Ord a => a -> a -> Bool

顺便说一句,如果你问 ghci 什么(<)是类型,它会正确回答。

Prelude> :t (<)
(<) :: (Ord a) => a -> a -> Bool

另请注意,在同一个类型类中已经有一个名为 的函数min

min :: Ord a => a -> a -> a

所以你不能调用你的函数min,除非你隐藏原来的min. (我不会向您展示如何操作。请为您的函数使用不同的名称。)


最后,你现在有

min :: Ord a => a -> a -> Bool
min a b = if a < b then True else False

正如莎拉所指出的,if blah then True else False与 相同blah,因此您可以简化为更清晰

min :: Ord a => a -> a -> Bool
min a b = a < b

现在 Haskell 中的操作符只是名称很有趣的函数 --- 这与

min :: Ord a => a -> a -> Bool
min a b = (<) a b

我们可以进一步简化:

min :: Ord a => a -> a -> Bool
min = (<)

所以你min只是一个不同的名字(<)。为什么不简单地使用原件<而不是您的min

于 2012-04-11T14:42:00.030 回答
8

已经有两个答案,但我认为缺少一个重要的点:

您需要在类型签名中的原因是您需要限制允许“进入”您的函数的类型。(Ord a) =>

当我定义一个函数function :: a -> a时,我是说我的函数将获取任何类型的数据,并返回一个相同类型的值。

A good example of this is head :: [a] -> a -- given a list of any type, head will return the list's first argument. This is because head doesn't really "touch" the data itself, so it doesn't matter at all what it is.

However, your situation isn't like that: imagine we have a data type Countries:

data Countries = USA | Nigeria | China | Canada -- yes, I know there are a few missing

It makes no sense to say min USA Canada or USA < Canada.

Therefore you have to restrict your functions to types which can be compared this way: types which have instances of the Ord (meaning ordered) typeclass. The way you restrict them is by writing (Ord a) => before your type signature.

于 2012-04-11T15:54:42.803 回答
7

您需要一个类型约束<才能工作:

min :: Ord a => a -> a -> Bool
--     ^^^^^
于 2012-04-11T14:30:51.173 回答