使用高阶函数查找列表的最大值

时间:2019-05-02 16:37:35

标签: haskell

我正在尝试使用过滤器(尽管我也可以使用map和/或foldr)来查找列表的max元素。

我尝试过滤掉小于max的每个数字,但它拒绝接受max作为过滤器参数。

这是我的代码:

 max' :: Ord a => [a] -> a
 max' xs = filter (< max) xs

这是我得到的错误:

* Couldn't match type `a' with `a0 -> a0 -> a0'
  `a' is a rigid type variable bound by
    the type signature for:
      max' :: forall a. Ord a => [a] -> a
    at Prog8.hs:50:1-25
  Expected type: [a0 -> a0 -> a0]
    Actual type: [a]
* In the second argument of `filter', namely `xs'
  In the expression: filter (< max) xs
  In an equation for max': max' xs = filter (< max) xs
* Relevant bindings include
    xs :: [a] (bound at Prog8.hs:51:6)
    max' :: [a] -> a (bound at Prog8.hs:51:1)

有没有一种方法可以在简单的过滤器函数中写入max'(或者可以将其与map或foldr结合使用)?

2 个答案:

答案 0 :(得分:1)

一个空列表没有最大元素,因此您不能使用所提供的类型编写总函数。一个更明智的选择是

maximum' :: Ord a => [a] -> Maybe a

最简单的方法是使用foldl'

maximum' = foldl' gom Nothing where
  gom Nothing new = Just new
  gom (Just old) new
    | old < new = Just new
    | otherwise = Just old

但是您想要foldr。由于foldl'实际上是根据foldr定义的,所以这很容易!

foldl' f b0 xs = foldr gof id xs b0
  where
    gof x r b = b `seq` r (f b x)

内联

maximum' xs = foldr gob id xs Nothing
  where
    --gob new r b = b `seq` r (gom b new)
    gob new r b = seq b $ r $
      case b of
        Nothing -> Just new
        Just old
          | old < new -> Just new
          | otherwise -> Just old

进行一些手动严格度分析,简化为

maximum' xs = foldr gob id xs Nothing
  where
    gob new r b = r $!
      case b of
        Nothing -> Just new
        Just old
          | old < new -> Just new
          | otherwise -> Just old

一个小小的警告:如果这是家庭作业,而您上交我的解决方案,您的老师可能会变得可疑。有一种更简单的方法,它的效率也低得多,但我会让您搜索它。

答案 1 :(得分:-1)

因此,首先,您发现想要的是:

max' :: Ord a => [a] -> [a]
max' xs = filter (< maximum xs) xs

如果由于某种原因您绝对致力于无点样式,并且只想使用高阶函数进行编写,那么这也将起作用:

max' :: Ord a => [a] -> [a]
max' = flip filter <*> ((>) <$> maximum)

但是不要那样做,太糟糕了。只需重复两次参数即可。