我是Haskell的初学者。我有一个我在Haskell中使用的元组列表:结构就像这样[(a,b),(c,d),(e,f),(g,h)]
我想要的是根据第二个值返回此元组中的最大元素:
因此,如果元组列表为[(4,8),(9,10),(15,16),(10,4)]
,我希望最大元素为(15,16)
。
但我不知道该怎么做。这是我到目前为止的尝试,
maximum' :: (Ord a) => (Num a) => [(a,b)] -> a
maximum' [] = error "maximum of empty list"
maximum' [(x,y)] = -1
maximum' (x:xs)
| snd x > snd(xs !! maxTail) = 0
| otherwise = maxTail
where maxTail = maximum' xs + 1
我收到此错误消息对我来说没有意义:
newjo.hs:23:25:
Could not deduce (a ~ Int)
from the context (Ord a, Num a)
bound by the type signature for
maximum' :: (Ord a, Num a) => [(a, b)] -> a
at newjo.hs:19:14-47
`a' is a rigid type variable bound by
the type signature for maximum' :: (Ord a, Num a) => [(a, b)] -> a
at newjo.hs:19:14
In the second argument of `(!!)', namely `maxTail'
In the first argument of `snd', namely `(xs !! maxTail)'
In the second argument of `(>)', namely `snd (xs !! maxTail)'`
我需要一些帮助来解决这个问题。
答案 0 :(得分:23)
惯用的方法是使用maximumBy (comparing snd)
。
a ~ Int
消息表示由于某种原因,Haskell推断a
必须是Int
,但类型签名不会将其限制为Int
。 As Amos notes in the comments和GHC告诉您其来源位置,这是因为您将其用作!!
的第二个参数,即Int
。
答案 1 :(得分:9)
使用库的惯用方法是使用maximumBy
。
maximumBy :: (a -> a -> Ordering) -> [a] -> a
然后剩下的就是定义a -> a ->
Ordering
类型的函数,因此它知道如何对元素进行排序。构造Ordering
对象的常用方法是使用
compare :: (Ord a) => a -> a -> Ordering
答案 2 :(得分:4)
到目前为止提供的解决方案非常优雅,您应该在您编写的任何实际代码中使用它们。但这是一个使用与您正在使用的相同模式匹配样式的版本。
maximum' :: Ord a => [(t, a)] -> (t, a)
maximum' [] = error "maximum of empty list"
maximum' (x:xs) = maxTail x xs
where maxTail currentMax [] = currentMax
maxTail (m, n) (p:ps)
| n < (snd p) = maxTail p ps
| otherwise = maxTail (m, n) ps
此解决方案避免了周围的杂耍索引,而只是跟踪当前最大元素,该元素在遍历整个列表时返回。避免使用列表的索引通常被视为良好做法。
答案 3 :(得分:1)
值得注意的是,Haskell中的元组是Ord的实例。因此可以对它们进行排序和比较。它们使用字典顺序排序(主要由元组的第一个元素,次要的第二个元素等),所以跟随:
maximum [(1,1),(1,8),(2,1),(2,6)] == (2,6)
如果你想得到最大二元素的元组。你可以只交换 maximum 函数的元组元素,然后像这样交换结果元素:
maximum' :: (Ord a, Ord b) => [(a,b)] -> (a,b)
maximum' l = swap $ maximum $ map swap l
where swap (x, y) = (y, x)
虽然为了使其工作,但两个元组元素必须是Ord的实例。