【问题标题】:Foldr Application文件夹应用程序
【发布时间】:2012-11-27 15:57:15
【问题描述】:

最近我正在尝试使用 Foldr 解决一个问题。任务如下:

In:[5,1,3,8,2,4,7,1]
Out:[16,8]

这意味着,我会将输入列表中位于奇数索引位置和偶数位的元素加倍。我在没有使用 foldr 的情况下编写了程序,如下所示:(它显示模式匹配失败:head[])

findPos list elt =
  map fst $ filter ((elt==).snd) $ zip [0..] list

doublePos [] = []
doublePos (x:xs)
  | ((head(findPos xs x)`mod` 2) /= 0) && (x `mod` 2 == 0) =
      [2*x] ++ doublePos xs
  | otherwise = doublePos xs

如何使用 foldr 编写这个程序?

【问题讨论】:

  • 这是一个奇怪的任务......这不是家庭作业,对吧?说真的,用foldr 这样做只会让它变得难以理解而没有任何好处。我只是一步一步地做:删除偶数索引元素,删除奇数条目,将剩余值加倍,完成。 map(*2) . filter even . remAtEvenPoswhere remAtEvenPos(a:b:l) = a:l; remAtEvenPos l = l。这就是惯用的 Haskell 解决方案。
  • @leftaroundabout thnx 为您提供建议。但作为初学者,我尝试使用 foldr 解决问题。
  • @leftaroundabout,你的意思是remAtEvenPos (a:_:l) = a : remAtEvenPos l
  • @dbaupp:当然有,不过现在编辑太晚了……

标签: haskell


【解决方案1】:

foldr 不是这个函数的好选择,因为您需要从列表的前面传递每个元素的索引的奇偶校验。

列表推导式可能是最简洁的:

doublePos xs = [2*x | (i,x) <- zip [0..] xs, even x, odd i] 

或者你可以使用普通的旧递归:

doublePos' (_:x:xs)
  | even x    = (2*x) : doublePos' xs
  | otherwise =         doublePos' xs
doublePos' _ = []

不过,如果你必须使用foldr,你可以通过让累加器成为一个函数来做到这一点 它将当前索引的奇偶校验作为参数:

doublePos'' xs = foldr step (const []) xs False where
  step x next p
    | p && even x = 2*x : next (not p)
    | otherwise   = next (not p)

【讨论】:

  • 非常感谢。不过,使用 foldr 的最终实现对我来说有点高。但我得到了递归解决方案。非常感谢
  • @SaugataBose:是的,累积一个函数有点奇怪,当有其他可用选项时,我不建议编写这样的代码。
【解决方案2】:

为什么您现有的代码会导致模式匹配失败:doublePos [5,1,3,8,2,4,7,1] 将第二个等式与 x = 5xs = [1,3,8,2,4,7,1] 匹配。这会导致 head (findPos [1,3,8,2,4,7,1] 5) 被评估,但这会减少到 head [] 并且您会得到错误。

对此进行扩展:您似乎希望从findPos 中得到的是当前元素的索引,相对于原始列表的开头。但是你实际上得到的是当前元素下一次出现的索引,相对于下一个元素......如果它不再出现,你会得到一个错误。

(此处使用字符作为列表元素以避免列表索引和列表元素之间的混淆。)

 0   1   2   3   4   5   6   7   8   9  10     <-- indices relative to start
'H':'e':'l':'l':'o':' ':'t':'h':'e':'r':'e':[] <-- original list
     |           |
x = 'e'          |               V                 say we're here
   xs = 'l':'l':'o':' ':'t':'h':'e':'r':'e':[]     head (findPos xs x) = 6 but we wanted 1
                 |               ^
            x = 'o'                                say we're here instead
               xs = ' ':'t':'h':'e':'r':'e':[]     head (findPos xs x) = error "head []" but we wanted 4

唯一可行的方法是将原始列表传递给findPos。但是您唯一可用的列表是您尚未递归到的原始列表的那部分。无论如何,如 hammar 的回答所示,有更好的方法来做到这一点。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-05-28
    • 2011-04-13
    • 2011-11-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-28
    • 2013-08-06
    相关资源
    最近更新 更多