Hi, This is a beginner’s question.
Could you please give examples for when one should use ‘map’ and when ‘mapA’ ?
Thank you!
Hi, This is a beginner’s question.
Could you please give examples for when one should use ‘map’ and when ‘mapA’ ?
Thank you!
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
@bernhard Thank you. This was very clear and helpful.
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.