2

我想定义一个函数,其参数接受一个列表和一个运算符。这是我目前拥有的。我正在尝试定义一个可以找到最小值或最大值的高阶函数。

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

但是,它目前无法正常工作。

4

3 回答 3

3

您可以编写一个接受任何函数参数的函数,或者使用可比较数据类型实现Orda -> a -> Bool的事实。

这是一段代码,显示了检查列表是否已排序的两种方法

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,EQGT(分别表示 <、= 和 >) 的数据类型。您可以通过传递可接受Ordering值列表或其他一些数据结构来使其更灵活,但是,在大多数情况下,第一个选项更合适。

于 2013-03-09T06:20:41.673 回答
1

GHC 不知道你想在你的代码中使用函数op作为操作符,你必须告诉他,但你怎么能这样做呢?

让我们考虑一下elem函数,该函数接受一个值和一个列表,并根据该值是否存在于列表中返回 True 或 False。

elem :: Eq a => a -> [a] -> Bool
elem 2 [1,2,3] => True

基本上它被视为一个函数,如果你想将它们用作一个真正有用的运算符,你必须用`将它括起来。

2 `elem` [1,2,3] => True

如果在 where 子句中加入 didierc 对 findType 调用的注释,就可以得到一个工作代码。

无论如何,将递归调用放入警卫是一个非常糟糕的主意,代码最难阅读,我不确定它是否会导致性能问题。你需要学习如何使用累加器,看看这个


注意
相反,当默认情况下将函数视为运算符时,要将其用作函数,只需用()将其括起来。

2 : [] => [2]

(:) 2 [] => [2]
于 2013-03-09T10:05:38.850 回答
1

您的代码是两个不同的问题。让我们首先解决生成编译器错误的问题。

您给findType了以下签名:

findType :: (a -> a -> Bool) -> [a] -> a

目的是从作为第二个参数给出的列表中提取由作为第一个参数提供的排序谓词所指示的边界。

但是,在 findType函数定义的最后一行中,您绑定maxTail到表达式findType xs,它省略了谓词。

正确的线路当然是:

where maxTail = findType op xs

你的第二个错误与largest函数的签名有关,但我会让你找出它到底是什么。

于 2013-03-09T08:12:36.543 回答