Map vs. mapA

Hi, This is a beginner’s question.

Could you please give examples for when one should use ‘map’ and when ‘mapA’ ?

Thank you!

3 Likes

Have a look at the docs section on looping and in particular the subsection on loops in with actions.

In short: the function that you are mapping over a list has to be “pure” in the case of map meaning it can’t have side-effects like reading or writing the ledger. The A in mapA means the function can perform actions - ie can have side-effects like reading from the ledger.

So if I had a list of integers and wanted to add one to each, that’s pure:

let numbersPlusOne = map (+ 1) [1,2,3]

If I had a list of contract IDs cids and wanted to fetch their contract arguments, that’s requires performing an action - reading from the ledger:

contract_args <- mapA fetch cids
4 Likes

@bernhard Thank you. This was very clear and helpful.

1 Like

Just for your reference: mapA isn’t special. You can implement it in terms of map and Prelude.sequence:

mapA : Applicative m => (a -> m b) -> [a] -> m [b]
mapA f = sequence . map f
-- or:
mapA f xs = sequence (map f xs)

sequence will take a list of some values in an Applicative context m, and turn them into a list in that context. As Action is a subclass of Applicative, this works for actions too.

sequence can be implemented something like this (untested code):

sequence : Applicative m => [m a] -> m [a]
sequence [] = pure []
sequence (x : xs) = (::) <$> x <*> sequence xs

This uses the <$> and <*> operators to run operations inside the Applicative context. These operators are defined differently for different contexts; you can read the definitions for lists if you like.

The Prelude actually implements it differently, but it’s equivalent, and it’s all Daml code that you could have written yourself if you wanted. :smiley:

1 Like