Haskell -将函数列表应用于变量



我一直在尝试实现一个函数,该函数将作为参数给定的函数列表应用于给定变量。我一直遇到各种类型错误与无限类型和类型不匹配。下面是使用递归的草稿,我相信它接近于工作,但不断遇到类型不匹配。我被困在这个问题的沼泽里,不知道如何前进。

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

相关内容

  • 没有找到相关文章

最新更新