Using Map.keys

Here we examine a very small snippet of code from a smart contract from the lecture.

The code from the smart contract in the Plutus Pioneer Lecture source code

let orefs   = fst <$> Map.toList utxos

Lets extract this into a function with the types explictly shown

getOrefs :: Map TxOutRef TxOutTx -> [TxOutRef]
getOrefs utxos = fst <$> Map.toList utxos

This code introduces a fair amount of unnecessary obscurification, it transforms Map TxOutRef TxOutTx to a [TxOutRef] this is simply the list of keys from the Map.

It transforms Map TxOutRef TxOutTx to a [(TxOutRef,TxOutTx)] (a list of pairs) via Map.tolist and then transforms the resulting list to a [TxOutRef] via <$>

Lets use the REPL to look at the functions we are using, we’ll set up a few REPL settings, import Data.Map as it is in smart contract, and verify the imports we have.

Prelude> :set -XTypeApplications
Prelude> :set -fprint-explicit-foralls
Prelude Map> import Data.Map as Map
Prelude Map> import Plutus.V1.Ledger.Tx
Prelude Map Plutus.V1.Ledger.Tx> :show imports
import Data.Map as Map
import Plutus.V1.Ledger.Tx
import Prelude -- implicit

Here the composed functions Map.toList, <$> and fst are detailed with the specialised types with the aid of TypeApplications

Map.toList This converts the Map to a list of key/value pairs

Prelude Map Plutus.V1.Ledger.Tx> :t +v Map.toList @TxOutRef @TxOutTx
toList @TxOutRef @TxOutTx
:: Map TxOutRef TxOutTx -> [(TxOutRef, TxOutTx)]

(<$>) This is used to transform [(TxOutRef, TxOutTx)] into [TxOutRef]

Prelude Map Plutus.V1.Ledger.Tx> :t +v (<$>) @[] @(TxOutRef,TxOutTx) @TxOutRef
(<$>) @[] @(TxOutRef,TxOutTx) @TxOutRef
  :: Functor [] =>
     ((TxOutRef, TxOutTx) -> TxOutRef)
     -> [(TxOutRef, TxOutTx)] -> [TxOutRef]

fst This simply extracts the first from a pair or a tuple, in this case the pair is a key and a value from an entry of Map TxOutRef TxOutTx, the first is the key which is a TxOutRef

Prelude Map Plutus.V1.Ledger.Tx> :t +v fst @TxOutRef @TxOutTx
fst @TxOutRef @TxOutTx :: (TxOutRef, TxOutTx) -> TxOutRef

Note <$> is an alias for the function fmap

Here we can see the use of fmap, to breakdown its use

getOrefs2 :: Map TxOutRef TxOutTx -> [TxOutRef]
getOrefs2 utxos = fmap (\(key,value) -> key) (Map.toList utxos)

getOrefs3 :: Map TxOutRef TxOutTx -> [TxOutRef]
getOrefs3 utxos = fmap (\(key,value) -> key) $ Map.toList utxos

getOrefs4 :: Map TxOutRef TxOutTx -> [TxOutRef]
getOrefs4 utxos = fmap fst $ Map.toList utxos

Map.keys has the exact type signature that we required in the extracted function getOrefs

Prelude Map Plutus.V1.Ledger.Tx> :t +v keys @TxOutRef @TxOutTx
keys @TxOutRef @TxOutTx :: Map TxOutRef TxOutTx -> [TxOutRef]

Here is a simplified version of the function

getOrefs :: Map TxOutRef TxOutTx -> [TxOutRef]
getOrefs utxos = Map.keys utxos

So the original code

let orefs   = fst <$> Map.toList utxos

can be changed to

let orefs   = Map.keys utxos