Cristi
Cristi

Reputation: 1328

Apply map using a different function to each element of the list

I currently have this bit of code:

function string keys = map (xor 1) (map ord string)

Which takes every element from the string and xor's it with 1. I would like to make the map function more advanced, by replacing 1 with any element from keys.

So for example if string == "Test" and keys = [1,3,6,9] I would get:

'T' xor 1
'e' xor 3
's' xor 6
't' xor 9

Is there a way to iterate over all element of keys so that I can achieve this? I'm pretty new to Haskell and I don't have a good grasp of its concepts.

My attempt at solving this was:

function string keys = map (iterate xor keys) (map ord string)

but I got a few errors and I guess it's because of the iterate function.

Any help would be greatly appreciated!


Just as I posted I noticed that iterate does a completely different thing so at this point I know why it doesn't work but I don't know how to replace it.

Upvotes: 0

Views: 778

Answers (2)

Will Ness
Will Ness

Reputation: 71065

That's what the ZipList instance of type class Applicative is doing:

 > getZipList $ xor      . ord <$> ZipList "Test" <*> ZipList [1,3,6,9, 11]
[85,102,117,125]

The get/ZipLists serve as kind of markers to signal our intent to zip, instead of the regular list's cross-product behaviour. We're supposed to pretend--"ignore" them, reading it in our minds instead as

-- zipWith   ( xor       . ord )           "Test"             [1,3,6,9, 11]

which is the same as

-- zipWith     xor (map    ord             "Test" )           [1,3,6,9, 11]
-- zipWith ($) (map (xor . ord)            "Test" )           [1,3,6,9, 11]
-- map (uncurry ($)) (zip (map (xor . ord) "Test" )           [1,3,6,9, 11] )
-- map (\(a,b)-> xor (ord a) b) (zip       "Test"             [1,3,6,9, 11] )

<$> is a synonym for fmap which is a synonym for map, and <*> is "apply".

Without the ZipList marker, we get

 >    [ord] <*> "Test"
[84,101,115,116]

--     ord  <$> "Test"
-- map ord      "Test"

Specifically, your code should be tweaked a little bit into

function :: [Char] -> [Int] -> [Int]
-- function string keys = map (iterate xor keys) (map ord string)
function string keys = zipWith ($) (map xor keys) (map ord string)
      -- = getZipList $ (xor <$> ZipList keys) <*> (ord <$> ZipList string)

($) is an application operator, ($) f x = f $ x = f x.

Upvotes: 0

Bakuriu
Bakuriu

Reputation: 101959

You want to associate one element of a list with one element of the other list. This is often called zipping. The zipWith seems to do exactly what you want:

Prelude Data.Bits> zipWith xor [1, 3, 5] [10, 23, 44]
[11,20,41]

It takes an a -> b -> c function, an [a] list and a [b] list and apply the function element wise with corresponding elements from the two lists.

It is a generalization of the zip function that produces pairs of element (zip = zipWith (,)).

Upvotes: 6

Related Questions