简体   繁体   English

我如何在 haskell 中修复这个更高阶的 function 代码?

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM