获取函数列表并使用值组合列表

时间:2013-06-10 02:37:34

标签: haskell function-composition

我目前正试图通过电子书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]

我认为它与类型签名有关,但到目前为止我没有尝试过任何结果。

1 个答案:

答案 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