Concat/collab dataset from multiple contracts and create another contract

Hi @Hem-M,

regarding usage of bindings I’ll refer to this answers of the question here & here on the forum, it explains well, what is different to them compared to variables you have in dynamic typed languages like Javascript. Besides, the question referred is very similar to yours.

However I’ll give here a try to explain a possible solution too.

So most important, DAML is based on Haskell. A mostly pure functional programming language. This means in practice that there don’t exist variables. There are only bindings. They are not mutable, otherwise they would have been called variables (you see the slight difference in naming here? It’s important to distinguish). However you can re-define a binding like this:

let foo = "hamspam"
[...]
let foo = "spam"

This may look like mutating foo but it’s really is just defining foo again with a different bound value.
So if you do something like this here:

let c = 2
let add a b = do
      let c = a
      b + c
add 2 3

the binding c which has been defined before the function add won’t magically be bound to a new value everytime you call add.

Now back to your code.

So I get the idea that you try to conditionally want to bind a value to data1 & data2 depending on what is in the parties list. However your current code (assuming one could mutate) has some flaws. Your call in the end with create ContractB with data1, data2 could result in usage of variables which have an empty string as a value, simply because it’s not guranteed that the value’s you’re effectively matching for aren’t in the list. However if this is your intention and assuming that you want that the last matching element in the list is used for data1 & the last non matching element is used for data2 then the adapted code probably looks like this:

data Either a b = Left a | Right b

controller CollabResult : ContractId MasterData
  with 
      parties : [Party]
  do 
    results <- forA parties \party -> do
                  (_, someData) <- lookupByKey @ContractAs (party, keyData)
                  if someData.party == party then Left someData.data1
                  else Right someData.data2
    let reversedResults = reverse results
    let optData1 = findOptional (\it ->
                      case it of
                        Left data1 -> Some data1
                        Right _ -> None) reversedResults
    let optData2 = findOptional (\it ->
                      case it of
                        Left _-> None
                        Right data2 -> Some data2) reversedResults
    let data1 = fromOptional "" optData1
    let data2 = fromOptional "" optData2
    create ContractB with data1, data2

Important to note here is that in comparison to your code, I respected the properties of how forA actually works.
forA is a function which returns not void (in daml called unit) but something of Update [A], which means a list of A's wrapped in an Update. To actually be able to do anything with this return type, you need to be within a contract declaration (which we currently are) and use YOURFANCYNAME <- such that the operation bind is executed on this value with it’s result being bound to YOURFANCYNAME.
The type of YOURFANCYNAME will then be of [A], so the unwrapped list which you now can operate on.

Besides, the code itself now maps your list of parties to a list of Either’s.
Now we want from that result the last left and last right as these are equivalent to the values which would have been assigned to data1 & data2 in your pseudo code. For searching these in the list we use findOptional, which returns the first matching entry going from the beginning to the end. Now, because we want to find the first matching entry from the end to the beginning, we need to reverse the list first, then we can do the search.

However, because it’s possible that the list never contains either an left xor right, the result of findOptional will always be something of Optional A (which means, there might be a value of A or not). To not fail here and continue, we can make use of the fromOptional function which takes first a default value and then the optional which should be checked for it’s value. If it does contain a value, this value is returned, if not your provided default value (in this case an empty string) is returned.

Now you’ve extracted data1 & data2 to use it for your call to create (which btw also returns something of Update A, however because it is the last statement in the do block it is fine to return as do blocks in contract definitions expect something of type Update A to be returned).

Finally, this logic seems to be a bit akward to me. I don’t recommend this code without knowing what exactly your intentions are here. I’m pretty sure that there is a different way to solve your idea :slight_smile:

3 Likes