适用于参数的函数列表

时间:2017-11-07 12:14:44

标签: haskell

任务是制作函数,获取一元函数列表(+ 1,* 2等)(3至少)并始终将它们应用于参数。例如:func 1 [(+1),(+ 1),(/ 2)] == 1.5。这就是我所做的:

compose x [(y),(c),(z)] =  map ($ x) [(z) . (c) . (y)]

但是如何制作无限的功能列表呢?如果用户想要3个以上的功能。 另一个问题是这个函数返回带有一个元素的列表而不是只有一个元素([4]而不是4)并且我有点坚持它

4 个答案:

答案 0 :(得分:4)

这应该可以解决问题:

compose x ys = foldl (\a b -> b a) x ys

这可以将ETA简化为

compose = foldl (\a b -> b a)

或者

compose x [] = x
compose x (y:ys) = compose (y x) ys

它将函数应用于输入,然后将该输入用作下一个输入,直到它到达列表的末尾,然后返回最终值。

λ> compose 1 [(+1), (+1), (/2)]
1.5
λ> compose 1 [(+1), (+1), (/2), (*10), (+(-1))]
14.0
λ> compose 1 []
1
λ> 

由于haskell如何解析缺陷,我认为你必须通过添加负数来减去函数。

如果用户必须输入至少3个功能,您可以这样做:

compose x ys
    | length ys < 3 = error "Must enter at least 3 functions!"
    | otherwise = foldl (\a b -> b a) x ys

或者,您可以返回一个Maybe,因为对于可恢复的内容,错误的风格不是很好。

compose x ys
    | length ys < 3 = Nothing
    | otherwise = Just $ foldl (\a b -> b a) x ys

答案 1 :(得分:3)

一般问题

您可以使用foldl:在这种情况下,您可以在列表中从左到右传递累加器,并对其执行一些操作:

所以你的compose看起来像是:

compose :: a -> [(a -> a)] -> a
compose x0 fs = foldl (??) x0 fs

现在问题是我们在??中做了什么。第一个参数是累加器,第二个参数是列表的一个元素,一个函数。所以我们必须实现类似的东西:

compose :: a -> [(a -> a)] -> a
compose x0 fs = foldl g x0 fs
    where g xi f = ...

因此,我们希望将f应用于xi以获取下一个xi。换句话说:

compose :: a -> [(a -> a)] -> a
compose x0 fs = foldl g x0 fs
    where g xi f = f xi

如果我们的目标是简化g函数,我们可以将它写成:

compose :: a -> [(a -> a)] -> a
compose x0 fs = foldl g x0 fs
    where g = flip ($)

并进一步改进:

compose :: a -> [(a -> a)] -> a
compose = foldl (flip ($))

然后产生:

Prelude> foldl (flip ($)) 1 [(+1)]
2
Prelude> foldl (flip ($)) 1 [(+1),(+1)]
3
Prelude> foldl (flip ($)) 1 [(+1),(+1),(/2)]
1.5

三个或更多元素

如果要将元素数量限制为三个或更多,我们可以使用模式匹配:

compose :: a -> [(a -> a)] -> a
compose x0 fs@(_:_:_:_) = foldl (flip ($)) x0 fs

虽然程序不应该在没有,一个或两个元素的列表上工作,这有点奇怪。

答案 2 :(得分:0)

只有两种情况,零功能或至少一种。

compose x [] = x
compose x (f:fs) = compose (f x) fs

答案 3 :(得分:0)

这可以通过使用foldr1通过翻转的撰写运算符级联列表函数来完成

Prelude> foldr1 (flip (.)) [(+5),(/2),(*3)] $ 1
9.0