【问题标题】:Writing a high order function to capture common pattern haskell编写一个高阶函数来捕获常见模式haskell
【发布时间】:2018-04-23 04:21:32
【问题描述】:
f1 [] = 1
f1 (x:xs) = x * f1 xs

f2 [] = 0
f2 (x:xs) = 1 + f2 xs

f3 [] = 0
f3 (x:xs) = x + f3 xs

f4 [] = []
f4 (x:xs) = x ++ f4 xs

这些都有一个共同的行为,我怎样才能准确地识别模式并编写一个高阶函数来捕获它?

【问题讨论】:

  • 使用该模式编写一个函数,并为您的案例中不同的所有内容添加一个参数。 (额外提示:使用函数作为参数来处理差异太大的所有内容)
  • 恭喜,您发现了Monoids!或folds,取决于你的观点。
  • 这些被称为折叠
  • 查找foldrfoldl
  • 我们甚至可以进一步概括:这实际上是一个catamorphism

标签: haskell functional-programming


【解决方案1】:

所有*您的函数都具有以下形式:

fn [] = P_0
fn (x:xs) = P_1 x (fn xs)

其中P_0P_1 是一些常量。我会调用P_0zeroP_1combine,并将它们添加到函数中:

-- P_0  P_1     list   = result
fn zero _       []     = zero
fn zero combine (x:xs) = combine x (fn zero combine xs)

我们去吧。现在我们有了f1 = fn 1 (*)f3 = fn 0 (+)f4 = fn [] (++)f2 有点奇怪,但你可以解决:f2 = fn 0 (\_ b -> b+1)

询问 GHCi 的类型给了我们fn :: b -> (a -> b -> b) -> [a] -> b,而Hoogling 告诉我们这个函数fn 实际上是函数foldr

foldr :: (a -> b -> b) -> b -> [a] -> b
--       ^combine         ^zero

你去吧:折叠,或者特别是正确折叠(foldr 中的r 表示正确)是您正在寻找的一般模式。

顺便说一句,还有折。我会让你试着弄清楚那些可能是什么。 Hoogle 也可以在这里为您提供帮助。

您可以在这里看到另一种模式,称为 Monoids,但我也将把它留给您,因为它似乎超出了这个问题的范围。


* 对于f2 (x:xs) = 1 + f2 xs,这可能看起来很奇怪,因为结果中没有x,但这只是P_1 a b = 1 + b 的情况,它在技术上仍然是相同的形式。

【讨论】:

    【解决方案2】:

    看起来你可以使用 foldr 来表示所有这些。

    foldr (*) 1 [1,2,3]  --f1
    
    foldr (\_ a-> 1 + a) 0 [1,2,3]  --f2
    
    foldr (+) 0 [1,2,3]  --f3
    
    foldr (++) [] ["a","b","c"]  --f4
    

    它们都需要一个列表、一个初始值和一个运算符。 他们都从右到左应用运算符:例如f1 [1,2,3] = 1*2*(3*1) 所以你可以使用foldr来参数化操作符和初始化值。

    【讨论】:

    • foldr (\_ a -> a + 1) 0 $ [1,2,3] 可能是f2 的更易于识别/消化的版本,而不是使用map (const 1)
    猜你喜欢
    • 1970-01-01
    • 2017-04-21
    • 1970-01-01
    • 1970-01-01
    • 2011-12-13
    • 1970-01-01
    • 2020-10-01
    • 2019-10-09
    相关资源
    最近更新 更多