简体   繁体   中英

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

it returns to me [101,202,303,404,505]

when i put h (*10) [1,2,3,4,5] then

i want to get [10,200,3000,40000,500000] list

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 :

h :: (a -> a) -> [a] -> [a]
h f = foldr (\x y -> f x :  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.

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 . That is, instead of applying an arbitrary function repeatedly, look for an efficient way to represent the compositions of the function. For example, (*x) can be represented by x , allowing (*x). (*y) (*x). (*y) to be represented by x*y .

To apply this idea, we first need to transform Willem's solution to make the compositions explicit.

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). 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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