我正在尝试实现一个简单的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 `<'
答案 0 :(得分:25)
如果您look at the documentation,您会看到(<)
的类型为
(<) :: 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
正如Sarah所说,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
?
答案 1 :(得分:8)
已经有两个答案,但我认为有一个重要的缺失:
您的类型签名中需要(Ord a) =>
的原因是您需要约束允许“进入”您的函数的类型。
当我定义一个函数function :: a -> a
时,我说我的函数将采用任何类型的数据,并返回相同类型的值。
一个很好的例子是head :: [a] -> a
- 给定一个任何类型的列表,head将返回列表的第一个参数。这是因为head并没有真正“触摸”数据本身,所以它根本不重要。
但是,你的情况不是这样的:假设我们有一个数据类型国家:
data Countries = USA | Nigeria | China | Canada -- yes, I know there are a few missing
说min USA Canada
或USA < Canada
是没有意义的。
因此,您必须将函数限制为可以这种方式进行比较的类型:具有Ord
(含义的)类型类实例的类型。限制它们的方法是在类型签名之前写(Ord a) =>
。
答案 2 :(得分:7)
您需要<
的类型约束才能工作:
min :: Ord a => a -> a -> Bool
-- ^^^^^