我需要编写一个接受函数列表和值的函数作为参数。必须依次对值中的每个函数应用。
例如,如果我的函数被称为compFuncs
...
compFuncs [f,g,h] val
相当于f(g(h val))
我已经知道使用foldr
在这里很有用,我可以在函数列表中的每个函数之间放置.
运算符,然后将其应用于val
。但是,我无法完成它,这是我的尝试......
compFuncs :: [(a->a->a)] -> a -> a
compFuncs [] val = val
compFuncs (x:xs) val = foldr //Im lost here
有人可以帮帮我吗?
答案 0 :(得分:8)
(我相信您打算将类型写为composeFuncs :: [a -> a] -> a -> a
,因为这是它的使用方式。)
foldr
通过使用您指定的替换替换列表的构造函数来工作。例如,foldr (+) 0 [1,2,3]
的工作原理是将列表[1,2,3]
(实际构建为1:2:3:[]
),并将(:)
替换为(+)
和[]
。 0
如下:
1 : 2 : 3 : []
1 + 2 + 3 + 0
如果您考虑要将某个值应用为[f,g,h]
的函数列表\x -> f (g (h x))
,我们可以通过查找foldr
的替换项找到(:)
和[]
。首先,让我们使用构图:
\x -> f (g (h x))
= (definition of (.))
\x -> (f . g . h) x
= (eta reduction)
f . g . h
这很接近,但我们必须对空列表构造函数执行某些操作。我们需要用某种“无所事事”或“空”功能来代替它。幸运的是,我们有id
,保证不会以任何方式改变结果:
f . g . h
= (definition of id)
f . g . h . id
现在我们可以看到折叠:
f . g . h . id
f : g : h : []
我们把它写成:
composeFuncs :: [a -> a] -> a -> a
composeFuncs = foldr (.) id
顺便说一下,可以像这样折叠的类型和一个充当“身份”的元素被称为monoids *,而a -> a
是Endo monoid。
*还有一项要求是,用于组合值的函数(例如(.)
的{{1}}或Endo
的{{1}})是关联的。你会注意到这使我能够在不需要括号的情况下展示它们。
对于发现此功能的另一种方法,让我们使用GHC 7.8的新型孔功能。首先,我们从(+)
开始定义一些漏洞:
Sum
当GHC类型检查时,我们得到一个类型错误,我将减少到相关的行:
composeFuncs
从composeFuncs :: [a -> a] -> a -> a
composeFuncs = foldr _f _z
开始,只有一种类型为tmp.hs:6:22: Found hole ‘_f’ with type: (a -> a) -> (a -> a) -> a -> a …
tmp.hs:6:25: Found hole ‘_z’ with type: a -> a …
的可能函数,即_z
。对于a -> a
,我们需要一个结合两个函数来提供新函数的函数。那当然是id
,所以我们写道:
_f