我目前正试图通过电子书Haskell音乐学院来解决这个问题:
定义一个函数applyAll,给定一个函数列表 [f1,f2,...,fn]和值v,返回结果f1(f2(...(fn v)...))。
例如: applyAll [simple 2 2,(+ 3)]5⇒20
目前我有
simple :: Integer -> Integer -> Integer -> Integer
simple x y z = x * (y + z)
applyAll :: [(f -> a)] -> a -> a
applyAll [f] v = foldr (.) v [f]
a = (applyAll [simple 2 2, (+3)] 5)
print a
这给了我错误:
Couldn't match type `f' with `a0 -> f'
`f' is a rigid type variable bound by
the type signature for applyAll :: [f -> a] -> a -> a
Expected type: (f -> a) -> a -> a
Actual type: (f -> a) -> (a0 -> f) -> a0 -> a
In the first argument of `foldr', namely `(.)'
In the expression: foldr (.) v [f]
我认为它与类型签名有关,但到目前为止我没有尝试过任何结果。
答案 0 :(得分:3)
这里的问题是.
的类型是(b->c) -> (a->b) -> a -> c
,但我们折叠的初始值不是函数。用英文来说,.
是函数组合,但我们想要函数应用。但是使用($)
可以很容易地解决这个问题。
($) f a = f a
所以
applyAll :: [(f -> a)] -> a -> a
applyAll [f] v = foldr ($) v [f]
接下来我们遇到[f]
部分的问题。所有这一切都匹配单个元素列表,这可能不是你想要的。
applyAll fs v = foldr ($) v fs
现在我们需要处理最后一部分,类型签名。我们的函数不能接受f -> a
类型的函数,因为当我们连接它们时,我们会在期望a
时为函数提供类型为f
的值。所以最终的结果是
applyAll :: [a -> a] -> a -> a
applyAll fs v = foldr ($) v fs