编写高阶函数来捕获常见模式haskell

rea*_*ado 15 haskell functional-programming

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
Run Code Online (Sandbox Code Playgroud)

这些都有一个共同的行为,我究竟如何识别模式并编写高阶函数来捕获它?

AJF*_*mar 19

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

fn [] = P_0
fn (x:xs) = P_1 x (fn xs)
Run Code Online (Sandbox Code Playgroud)

在哪里P_0P_1是一些常数.我将调用P_0 zero,P_1 combine并将它们添加到函数中:

-- P_0  P_1     list   = result
fn zero _       []     = zero
fn zero combine (x:xs) = combine x (fn zero combine xs)
Run Code Online (Sandbox Code Playgroud)

我们走了.现在我们有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
Run Code Online (Sandbox Code Playgroud)

所以你去:褶皱,或特别的权利倍(将rfoldr指右)是你要找的一般模式.

顺便说一句,还有褶皱.我会让你试着弄清楚那些可能是什么.Hoogle也可以帮助你.

你可以在这里看到另一种模式,叫做Monoids,但我也会把它留给你,因为它似乎超出了这个问题的范围.


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


Joh*_*iao 7

看起来您可以使用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
Run Code Online (Sandbox Code Playgroud)

它们都需要列表,初始值和运算符.它们都从右到左应用运算符:例如f1 [1,2,3] = 1*2*(3*1) ,您可以使用foldr参数化运算符和init值.

  • `foldr(\ _ a - > a + 1)0 $ [1,2,3]`可能是一个稍微容易识别/消化的`f2`版本,而不是使用`map(const 1)`. (3认同)