CamelBak
CamelBak

Reputation: 105

Apply a Function to every element in a list

I've created a function m such that

m "abc" "def" == "bcd" 

and I would like to create another function that uses m to generate the output ["bcd","efg","hia"] when given the input ["abc","def","ghi"]

The definition of m is

m :: [a] -> [a] -> [a]
m str1 str2 = (drop 1 str1) ++ (take 1 str2)

Upvotes: 5

Views: 177

Answers (3)

Enlico
Enlico

Reputation: 28384

import Data.List.HT (rotate)
m2 :: [[a]] -> [[a]]
m2 list = zipWith m list (rotate 1 list)

where m is yours.

You can make it point free in a couple of ways.

Here's using the Applicative style,

m2 :: [[a]] -> [[a]]
m2 = zipWith m <$> id <*> (rotate 1)

which can read as m2 is the function that passes its argument to id and rotate 1 respectively, and then those results to zipWith m.

Here's using the Monadic style,

import Control.Monad (ap)
m2 :: [[a]] -> [[a]]
m2 = zipWith m `ap` rotate 1

which is imho a bit less clear, in this case; you can read it as m2 passes its argument to both zipWith m and rotate 1 and then feeds the result of the latter to the the result of the former.

Honestly, I like the other answer a bit more, as it avoids importing rotate and gets the same effect with tail . cycle.

Upvotes: 3

willeM_ Van Onsem
willeM_ Van Onsem

Reputation: 476557

You can make use of zipWith :: (a -> b -> c) -> [a] -> [b] -> [c] here where you take the entire list as first parameter, and tail (cycle l) as second parameter (with l the list):

combine :: [a] -> [a]
combine l = zipWith m l (tail (cycle l))

zipWith will enumerate concurrently on both lists and each time call m with an element of the first and the second list. For example:

Prelude> combine ["abc","def","ghi"]
["bcd","efg","hia"]

Upvotes: 4

Aplet123
Aplet123

Reputation: 35502

You can append the first element to the end to simulate a wrap-around, then zip the list with its tail to get tuples of each element, then map it:

f :: [[a]] -> [[a]]
f [] = []
f l@(x:xs) = map (\(a, b) -> m a b) $ zip wrapped (tail wrapped)
    where wrapped = l ++ [x]

Alternatively, you can use uncurry:

f :: [[a]] -> [[a]]
f [] = []
f l@(x:xs) = map (uncurry m) $ zip wrapped (tail wrapped)
    where wrapped = l ++ [x]

Upvotes: 3

Related Questions