【问题标题】:Find max of list using higher order function使用高阶函数查找列表的最大值
【发布时间】:2019-05-02 16:37:34
【问题描述】:

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

我尝试过滤掉每个小于 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 结合使用)?

【问题讨论】:

  • max 实现为折叠很容易。 (我认为列表上的任何递归函数都可以作为折叠来完成。)但你绝对不能只使用map 和/或filter。 (好吧,我不明白怎么做,但有人可能会证明我错了:))
  • 我可以用 foldr 做吗?我正在尝试使用 foldr、map 和 filter。
  • 是的,你当然可以。您的累加器只是“迄今为止”的最大值。您可能想要foldr1 而不是foldr(它在空列表上崩溃,但max 也是如此)。
  • 刚刚实现了求列表最大值的函数其实是maximummax取2个普通值,返回较大的值)
  • 使用您拥有的类型签名,max' [] 可以返回的唯一明智的事情是⊥。如果您可以重组您的调用代码,使其可以使用Ord a =&gt; NonEmpty a -&gt; aOrd a =&gt; [a] -&gt; Maybe a,则可以避免使用⊥。

标签: haskell


【解决方案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

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

【讨论】:

    【解决方案2】:

    首先,正如您所发现的,您想要的是:

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

    如果您出于某种原因绝对专注于无点样式,并且只想使用高阶函数进行编写,这也可以:

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

    但不要这样做,这太糟糕了。重复两次即可。

    【讨论】:

    • 这不进行类型检查。
    • 对不起,我从问题中取了类型,而提问者要求的显然需要不同的类型。固定。
    • 我怀疑那是他们真正的意图。
    • 我觉得这很有帮助,不知道为什么它被否决了。
    • 我在这里度过了不赞成的一天;见stackoverflow.com/q/55957477/107331。在这种情况下,我回答了我认为您要问的问题“找到小于最大值的所有元素”,而不是您提出的问题。
    猜你喜欢
    • 2023-01-11
    • 2014-02-17
    • 1970-01-01
    • 2022-01-15
    • 2018-09-13
    • 1970-01-01
    • 1970-01-01
    • 2015-05-03
    • 2015-09-29
    相关资源
    最近更新 更多