[英]How can i fix this higher order function code in haskell?
I want to fix this code我想修复这段代码
h :: (a -> b) -> [a] -> [b]
h f = foldr (\x y -> f x : y) []
if i put h (+100) [1,2,3,4,5]
in GHCI如果我将
h (+100) [1,2,3,4,5]
放入 GHCI
it returns to me [101,202,303,404,505]
它返回给我
[101,202,303,404,505]
when i put h (*10) [1,2,3,4,5]
then当我把 h
(*10) [1,2,3,4,5]
然后
i want to get [10,200,3000,40000,500000]
list我想获得
[10,200,3000,40000,500000]
列表
can anyone help me fixing this code?谁能帮我修复这段代码?
You here implemented a map
, but in order to repeat the same operation multiple times, you need to perform a mapping on the tail y
:您在这里实现了一个
map
,但是为了多次重复相同的操作,您需要对尾部y
执行映射:
h :: (a -> a) -> [a] -> [a]
h f = foldr (\x y -> f x :
map f y) []
Solving the general problem, as Willem Van Onsem's answer does, requires O(n^2)
time to calculate the first n
elements, because the function has to be applied k
times to calculate the k
th element.正如Willem Van Onsem 的回答那样,解决一般问题需要
O(n^2)
时间来计算前n
元素,因为 function 必须应用k
次才能计算第k
个元素。
To solve this sort of problem efficiently , you will need to take advantage of some additional structure.为了有效地解决这类问题,您需要利用一些额外的结构。 Based on your examples, I think the most obvious approach is to think about semigroup actions .
根据您的示例,我认为最明显的方法是考虑semigroup actions 。 That is, instead of applying an arbitrary function repeatedly, look for an efficient way to represent the compositions of the function.
也就是说,与其重复应用任意 function ,不如寻找一种有效的方法来表示 function 的组合。 For example,
(*x)
can be represented by x
, allowing (*x). (*y)
例如,
(*x)
可以用x
表示,允许(*x). (*y)
(*x). (*y)
to be represented by x*y
. (*x). (*y)
由x*y
表示。
To apply this idea, we first need to transform Willem's solution to make the compositions explicit.为了应用这个想法,我们首先需要转换 Willem 的解决方案以使组合明确。
h :: (a -> a) -> [a] -> [a]
h f0 as0 = go as0 f0
where
go [] _ = []
go (a:as) f = f a : go as (f0 . f)
If we like, we can write that as a fold:如果我们愿意,我们可以把它写成折叠:
h :: (a -> a) -> [a] -> [a]
h f0 as = foldr go stop as f0
where
stop _ = []
go a r f = f a : r (f0 . f)
Now we've structured the function using an accumulator (which is a function).现在我们已经使用累加器(这是一个函数)构建了 function。 As we compose onto the accumulator, it will get slower and slower to apply it.
当我们在累加器上作曲时,应用它的速度会越来越慢。 We want to replace that accumulator with one we can "apply" quickly.
我们想用一个我们可以快速“应用”的累加器来替换那个累加器。
{-# language BangPatterns #-}
import Data.Semigroup
repeatedly :: Semigroup s => (s -> a -> a) -> s -> [a] -> [a]
repeatedly act s0 as = foldr go stop as s0
where
stop _ = []
go a r !s = act s a : r (s0 <> s)
Now you can use, for example,现在您可以使用,例如,
repeatedly (\(Product s) -> (s*)) (Product 10) [1..5]
==> [10,200,3000,40000,500000]
repeatedly (\(Sum s) -> (s+)) (Sum 100) [1..5]
==> [101,202,303,404,505]
In each of these, you accumulate a product/sum which is added to/multiplied by the current list element.在其中的每一个中,您都会累积一个乘以当前列表元素的乘积/总和。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.