所以我想在 Haskell 中编写一个名为 Largest 的函数,它找到列表的最大元素,但使用高阶函数实现。
我是 Haskell 的新手,所以这是我的尝试,但它不起作用
largest :: [Int] -> Int
largest [] = 0
largest (head : tail) = if (head > tail) then head
else (largest tail)
我不知道高阶函数是什么意思。
一些帮助将不胜感激。
所以我想在 Haskell 中编写一个名为 Largest 的函数,它找到列表的最大元素,但使用高阶函数实现。
我是 Haskell 的新手,所以这是我的尝试,但它不起作用
largest :: [Int] -> Int
largest [] = 0
largest (head : tail) = if (head > tail) then head
else (largest tail)
我不知道高阶函数是什么意思。
一些帮助将不胜感激。
To fix your attempt:
largest :: [Int] -> Int
largest [] = 0
largest (head : tail) = max head (largest tail)
Note that this will work only for non-negative numbers (you can fix this either by deciding that empty lists have no maximum - like Prelude's maximum
, or by using the minBound
for Int
instead of 0
, but this wouldn't work e.g. for Integer
).
However, this still doesn't use a higher order function. A suitable function for this kind of problem would be foldl
(or better Data.List.foldl'
) or foldr
, but I don't want to spoil the fun.
高阶函数将一个或多个函数作为其参数之一,或返回一个函数。在这种情况下,我假设高阶参数应该是一个比较函数。这给出了最大的简单定义:
largest :: [a] -> (a -> a -> Ordering) -> a
largest (x:xs) cmp = go x xs
where go largest [] = largest
go largest (x:xs) = case cmp largest x of
LT -> go x xs
_ -> go largest xs
另外,只是为了让您知道,在 Prelude 中有一个功能可以为您执行此操作,称为maximum
.maximum [2,3,4,1] == 4
要完成现有答案,
您必须克服的第一个问题是尝试编译您的代码,或者至少要理解错误消息。这个提示应该给你很好的指导你所面临的问题以及如何修改它以获得正确的版本(即使你没有满足高阶功能要求,至少你会有一个工作的)。
为此,让我们看一下模式子句的类型签名,(head : tail),
首先对于 (:) 函数,我们有,
(:) :: a -> [a] -> [a]
然后我们为head和tail推导出以下类型(它们是 (:) 的参数),
再次,让我们看一下 (>) 的类型签名
(>) :: Ord a => a -> a -> Bool
如果我们省略约束类,为了简单起见,我们有,
(>) :: a -> a -> Bool
或者在你的代码中有,
....
if ( head > tail) ...
....
可以重写,再次简化,为
....
if ((>) head tail)) ...
....
使用前面的所有注释,您应该能够重建提供给 (>) 函数的类型并理解问题。
然后您可以更正您的代码并使其正常工作。
之后你可以看看高阶函数,然后把它改正。
作为一般评论,当您遇到一个复杂的问题时,请尝试将其分解为较小的问题,并针对每个子问题尝试应用以下烹饪原则。
让它工作,
让它正确,
如果快的话。
if (head > tail)
首先,您不需要括号。其次,更严重的是,head
是一个整数,但tail
它是一个整数列表。你不能比较这两件事。
largest (head : tail) = if (head > tail) then head
else largest tail
这没有正确缩进。else
必须至少缩进if
到. 您可以将 thethen
和 theelse
放在同一行,或者执行类似的操作
if head > tail
then head
else largest tail
(同样,您实际上并不需要括号 - 尽管它们不会造成任何伤害。)
最后一点,有一个预定义的函数叫做head
,还有一个叫做tail
,所以这些不是变量名的最佳选择。惯用的 Haskell 选择是x
and xs
(“x”的复数形式)。你会看到很多这样写的代码。它还有助于提醒您这x
是一个事物并且xs
是事物的列表。