我想定义一个函数,其参数包含一个列表和一个运算符。这就是我现在拥有的。我正在尝试定义一个可以找到最小值或最大值的高阶函数。
largest :: (a -> a -> Bool) -> a
largest = findType (>)
findType :: (a -> a -> Bool) -> [a] -> a
findType op [] = error "empty list"
findType op [x] = x
findType op (x:xs)
| x op maxTail = x
| otherwise = maxTail
where maxTail = findType op xs
但是,它目前无法使用。
答案 0 :(得分:3)
您可以编写一个接受任何a -> a -> Bool
函数参数的函数,也可以使用可比数据类型实现Ord类的事实。
这是一段代码,显示检查列表是否已排序的两种方法
option1 :: (a->a->Bool) -> [a] -> Bool
option1 op (a:b:ls) = op a b && option1 op (b:ls)
option1 op _ = True
option2 :: (Ord a) => Ordering -> [a] -> Bool
option2 op (a:b:ls) = compare a b == op && option2 op (b:ls)
option2 op _ = True
main = do
let ls = [1, 2, 3]
print $ option1 (<) ls
print $ option2 LT ls
请注意,第二种方法需要使用Ordering
数据类型,其中只有值LT
,EQ
和GT
(分别表示&lt;,=和&gt; )。您可以通过传递可接受的Ordering
值列表或其他一些数据结构来使其更灵活,但是,在大多数情况下,第一个选项更合适。
答案 1 :(得分:1)
您的代码有两个不同的问题。让我们先解决生成编译器错误的问题。
您向findType
提供了以下签名:
findType :: (a -> a -> Bool) -> [a] -> a
意图是从作为第二个参数给出的列表中提取绑定,作为第一个参数提供的排序谓词。
但是,在非常findType
函数定义的最后一行中,您将maxTail
绑定到表达式findType xs
,这将省略谓词。
正确的路线当然是:
where maxTail = findType op xs
您的第二个错误与largest
功能的签名有关,但我会让您确切地知道它是什么。
答案 2 :(得分:1)
GHC并不知道您希望将 op 函数用作代码中的运算符,您必须告诉他,但您怎么能这样做?
让我们考虑 elem 函数,这个函数取一个值和一个列表,并返回True或False,具体取决于该值是否存在于列表中。
elem :: Eq a => a -> [a] -> Bool
elem 2 [1,2,3] => True
基本上它被视为一个函数,如果你想将它们用作一个非常有用的运算符,你必须用`将它括起来。
2 `elem` [1,2,3] => True
如果在find子句的调用中将didierc的注释添加到where子句中,您将拥有一个正常工作的代码。
无论如何,将一个递归调用放入一个警卫是一个非常糟糕的主意,代码是最难读的,我不确定它是否会导致性能问题。您需要了解如何使用累加器,请查看this
注意强>
相反,当默认情况下将某个函数视为运算符时,要将其用作函数,只需将其与()括起来。
2 : [] => [2]
(:) 2 [] => [2]