How `coerceContractId` is used in the ledger export script?

If I apply the ledger export tool to the skeleton template, I get the following script, which replays the ledger history:

-- | Test 'export' with freshly allocated parties and
-- no replacements for missing contract ids.
testExport : Script ()
testExport = do
  parties <- allocateParties
  let contracts = DA.TextMap.empty
  export Args with ..

-- | The Daml ledger export.
export : Args -> Script ()
export Args{parties, contracts} = do
  let alice1220dfe521ccae0f585dc76c3c250170e3ac3bcda3fba26bd64df6e1ff83629321bf_0 = lookupParty "Alice::1220dfe521ccae0f585dc76c3c250170e3ac3bcda3fba26bd64df6e1ff83629321bf" parties
  let bob1220dfe521ccae0f585dc76c3c250170e3ac3bcda3fba26bd64df6e1ff83629321bf_0 = lookupParty "Bob::1220dfe521ccae0f585dc76c3c250170e3ac3bcda3fba26bd64df6e1ff83629321bf" parties
  (coerceContractId @_ @Main.Asset -> asset_1_0) <- submit alice1220dfe521ccae0f585dc76c3c250170e3ac3bcda3fba26bd64df6e1ff83629321bf_0 do
    createCmd (Main.Asset {issuer = alice1220dfe521ccae0f585dc76c3c250170e3ac3bcda3fba26bd64df6e1ff83629321bf_0,
        owner = alice1220dfe521ccae0f585dc76c3c250170e3ac3bcda3fba26bd64df6e1ff83629321bf_0,
        name = "TV"})
  (coerceContractId @_ @Main.Asset -> asset_2_0) <- submit alice1220dfe521ccae0f585dc76c3c250170e3ac3bcda3fba26bd64df6e1ff83629321bf_0 do
    exerciseCmd asset_1_0 (Main.Give {newOwner = bob1220dfe521ccae0f585dc76c3c250170e3ac3bcda3fba26bd64df6e1ff83629321bf_0})
  _ <- submit bob1220dfe521ccae0f585dc76c3c250170e3ac3bcda3fba26bd64df6e1ff83629321bf_0 do
    exerciseCmd asset_2_0 (Main.Give {newOwner = alice1220dfe521ccae0f585dc76c3c250170e3ac3bcda3fba26bd64df6e1ff83629321bf_0})
  pure ()

What does coerceContractId do in this script?

What does the syntax with the right arrow mean?: coerceContractId @_ @Main.Asset -> asset_1_0

(coerceContractId` is also used in connection with interfaces which are already stable, still I couldn’t find anything about it in the docs.)

Hi @gyorgybalazsi, thank you for your questions.

What does coerceContractId do in this script?

coerceContractId is a function from DA.Internal.LF (and reexported from Prelude) with type ContractId a -> ContractId b; it simply changes the type index of a ContractId without changing its value. This is necessary in the generated code since the same ContractId might be used at different types, e.g. when exercising interface choices. This function used to be hidden from the docs but after PR #16180, prompted by your question, it should appear there, so thanks for bringing it to our attention.

What does the syntax with the right arrow mean?: coerceContractId @_ @Main.Asset -> asset_1_0

This is a feature inherited from GHC Haskell known as View Patterns. Note that the view pattern requires the parens, i.e. (coerceContractId @_ @Main.Asset -> asset_1_0). It is equivalent to applying the function on the LHS (coerceContractId @_ @Main.Asset) of the arrow to the result of the action on the right of the pattern (<- submit ...) and binding the result of that to the variable asset_1_0.

Also, in case you’re not familiar with them, the @ syntax is another feature inherited from GHC Haskell, Type Applications. The type of coerceContractId : ContractId a -> ContractId b has type variables a and b, and here we want to return a ContractId Main.Asset, so we must set b ~ Main.Asset. Since a comes first, we skip it with @_, which means it can unify with any type, and then we use @Main.Asset to unify b with Main.Asset .

2 Likes

Thank you, now I understand it.