我一直在尝试实现一个函数,该函数将作为参数给定的函数列表应用于给定变量。我一直遇到各种类型错误与无限类型和类型不匹配。下面是使用递归的草稿,我相信它接近于工作,但不断遇到类型不匹配。我被困在这个问题的沼泽里,不知道如何前进。
applyList :: [a -> b] -> a -> [b]
applyList [] variable = variable
applyList (f:fs) variable = applyList fs $(f variable -> f variable)
这是我使用文件夹的另一个草案解决方案,也没有成功。
applyList :: [a -> a] -> a -> a
applyList fs variable = foldl (variable f -> f variable) variable fs
使用例子:
applyList [] "foo" ==> "foo"
applyList [] 1 ==> 1
applyList [(++"bar")] "foo" ==> "foobar"
applyList [reverse, tail, (++"bar")] "foo" ==> "raboo"
applyList [(3*), (2^), (+1)] 0 ==> 6
applyList [(+1), (2^), (3*)] 0 ==> 2
看起来您正在尝试编写两个不同的函数。让我们分别来看一下。如果你想要这个签名,
applyList :: [a -> b] -> a -> [b]
则需要将每个函数应用于输入并获得结果列表。不需要。您可以简单地在递归的每一步将f
应用于变量。
applyList :: [a -> b] -> a -> [b]
applyList [] _ = []
applyList (f:fs) variable = f variable : applyList fs variable
现在,Haskell为处理列表和数据结构提供了许多高级操作符,因此这种显式递归并不像您想象的那样经常需要。特别是,您的applyList
实际上只是map
函数。
applyList :: [a -> b] -> a -> [b]
applyList fs a = map (f -> f a) fs
f -> f a
可简化为算子段
applyList :: [a -> b] -> a -> [b]
applyList fs a = map ($ a) fs
现在看第二个。如果这是你的目标
applyList :: [a -> a] -> a -> a
那么你想要折叠是对的。根据您的示例输入和输出,看起来您希望首先应用最右边的函数,因此我们可以使用foldr
applyList :: [a -> a] -> a -> a
applyList fs a = foldr (f a -> f a) a fs
再说一遍,f a -> f a
只是($)
的一种可爱的写法
applyList :: [a -> a] -> a -> a
applyList fs a = foldr ($) a fs
如果你现在看不清楚,不要担心。坚持你的递归定义,如果你觉得更舒服的话。这种更高层次的思考是随着使用Haskell的时间和经验而来的,如果你继续做你正在做的事情,我保证你会到达那里。
请记住,列表的第一个元素应该是最外层的函数,这意味着您不需要向后执行任何操作或使用foldl
。明确地写下来,应该是这样的:
applyList [] variable = variable
applyList (f:fs) variable = f (applyList fs variable)
和foldr
:
applyList = foldr (.) id
或者更好:
applyList fs variable = foldr ($) variable fs