Addition Assignment

Hi Team,

Do we have addition assignment(+=, -=, etc) operator in DAML?

Example:
let a= 10.0, b= 20.0
a+=b (or) a= a+b

When I tried above example DAML is not allowing the syntax and throwing recursive variable declaration error.
I have looked into the documentation but no luck. If we have addition assignment capability, could someone please point me to the right documentation.

2 Likes

Hi @Sneha, values in DAML are always immutable. So addition assignment doesn’t exist because you can never mutate a value and add to it.
You might think that the following example mutates a value:

test = do
  let a = 10.0
  let a = 11

However, you are not mutating a. The third line in this example will create a new value called a which shadows (hides) the exsiting a defined in line 2.

3 Likes

In the binding let a = a + b, the a on the right of the = refers to the a on the left of the =. This is so that the reference behavior of functions and variables, whether in let or at the top-level, is unified; consider this to be like

let a () = a () + b

except that you get the error at compile-time.

It’s generally worth the debate whether you ought to have two forms of let instead, one with the current behavior and one with the nonrecursive behavior. However, we must choose the confusion we want:

  1. having two lets
  2. you must use a fresh variable name each time a replacement is desired

There is more confusion in (1) than it might seem: even if we had nonrecursive let, it would only introduce a new binding, as @cocreature mentions, not alter the previous binding, so any code that referred to the prior binding would not see the new binding. So to extend his example, if you wrote

  letnonrec a = 10.0
  letnonrec f x = a + x
  letnonrec a = a + 1
  f 0

this would evaluate to 10, not 11.

You may use any convention you like for fresh variable names, but a common one is to add '. So you might write let a' = a + b. If we consider the above example written in this style, it is far more obvious that the result will be 10:

let a = 10.0
    f x = a + x
    a' = a + 1
f 0
2 Likes

Okay I get this. Let me try once.
I am trying to achieve below scenario wherein variable a scope should be the out of for loop and capable to use it inside for.

let a = 0

forA quantity list(quantity => do
      a = a + quantity)
2 Likes

There is a good chance that forA is not the function you want to use here. That’s because the function you pass to it is only allowed to depend on the argument (quantity), and the only form of “sequence”, or things happening in a particular order, comes from the actions you are performing with the do. Specifically, variable binding is not such an action; it is purely a local alias for a value, and cannot escape its scope of definition. (To put it another way, DAML functions must be true functions, whose only “effect” is in accepting arguments and returning values.)

You might be comfortable with forA from examples. However, it is not a “one size fits all” function for working across the aggregate of a list; it is used in those examples because it hides some details of lists that are sometimes useful, but not always. If there is any “one size fits all” function for lists, it’s foldr or foldl as @cocreature used previously, but you won’t see foldr in most examples, because it is much nicer in DAML to use a function that more closely fits your use case, and foldr is far too powerful and general-purpose for that.

To determine what the proper function to use instead of forA is, first decide: are you performing any actions from the function you’re passing in, such as contract exercises or creates? If you are, a good starting point is the DA.Action module; if you are not, check the DA.Foldable module instead. Regardless, the starting point is to make that determination.

1 Like

I also want to use this opportunity to plug the excellent Functional Programming 101 section in our documentation @bernhard added recently. In particular, the section around looping.

2 Likes

Thank you for the detailed explanation @Stephen.
Will see the api of action and foldable first and then try to work on my problem.

1 Like

This document helps @cocreature. Thank you.

1 Like

The generic looping construct over a list in DAML is foldl. You can think of it as walking down the list from left to right and, on each element, doing some operation while carrying over the result. The general form is:

foldl function_on_each_element initial_value list

where function_on_each_element is a function of two arguments, the accumulated value so far and the new element we’re considering, and must return the new accumulated value. This raises the question of what the “accumulated value so far” is when considering the first element, and that is precisely what the initial_value is there for. The final return value of foldl is the accumulated value after processing the last element.

In your case, this means you’d have:

foldl (\soFar newElem -> soFar + newElem) 0 quantityList

where \soFar newElem -> soFar + newElem is a function that represents what to do on each step (quantity => do a = a + quantity) and 0 is the initial value (Let a = 0).

Note that in this case we can use a syntactic trick to make this shorter. This is completely optional and up to you whether you think this makes your code better. Here is the trick. First, variable names in a function don’t really matter outside of it, so \soFar newElem -> soFar + newElem is really the same as \a b -> a + b. This is really just addition, though. In DAML, a binary operator like + can be turned into a function by wrapping it in parentheses, so (+) is exactly the same as \a b -> a + b. This means we can also write:

foldl (+) 0 quantityList

Finally, for this case the standard library also happens to have a builtin function to directly do what you want: sum quantityList.

3 Likes

Great! Thank you Gary_Verhaegen. This helps.

1 Like

Hi Sneha,

In case that this wasn’t just a proxy example and you really want to only add up a list of numbers, there’s a utility function in the stdlib for that purpose:

sum quantityList

I hope that (still) helps, M.

1 Like

I ran into an issue with a similar example and the compiler gives me the following error message:

• Couldn't match expected type ‘Update a0’ with actual type ‘Int’
• In a stmt of a 'do' block:
    foldl
      (\ quantity a -> quantity + a)
      0
      newlist
  In the expression:
       foldl
         (\ quantity a -> quantity + a)
         0
         newlist

In my example “a” is defined as a “Decimal” type

1 Like

Hi @bartcant,

It’s a bit hard to tell for sure without more context on the surrounding code, but here’s a guess: the code

foldl (\quantity a -> quantity + a) 0 newlist

is inferred to be of type Int (which seems reasonable for a sum), but the context in which it appears would have expected an expression of type Update a. The easiest way to transform a value into an Update wrapping that value is to use the function pure, so perhaps changing your code to:

pure $ foldl (\quantity a -> quantity + a) 0 newlist

will work.

Note that return and pure are exactly the same function; which one you use depends entirely on your personal preferences.

Also note that (\quantity a -> quantity + a) is semanticaly equivalent to (+), but may be slower depending on implementation details (I’m not vey familiar with the internals of the compiler here; @Sofia_Faro is probably best placed to opine).

1 Like