Question on DAML function

f (x: B): A = phi is top-level definition, and
c is a constant of type
B . Is it possible to define
f and
c in such a way that
(f c)
will yield two different results in two different contexts?

2 Likes

Hi @upanshu21 and welcome,

no, it’s not possible. DAML is a pure language, so its functions are “referentially transparent”, meaning that given the same argument, the function always returns the same result. The one kinda-sorta exception are Update return values. In this case, the function, when given the same argument also always gives the same Update, but the Update then may be executed by the Ledger, and this execution depends on the environment (mapping of contract IDs to contracts).

1 Like

I think it can depend on your definition of “context” (and also your definition of B, and probably your definition of “yield”).

If you want to do something stateful (and don’t mind some complicated type definitions), you can use DA.Action.State, a.k.a. the State monad. Without knowing your understanding of monads, I’m not sure if this makes sense to you, so I’ll try to explain.

Using DA.Action.State should allow for something like:

test = scenario do
  let (_, x) = flip runState 0 $ do
        a <- get -- a == 0
        modify ( +1)
        b <- get -- b == 1
        modify (+ 1)
        c <- get -- c == 2
        modify (+ 1)

  x === 3

This is because get (in this context) doesn’t return an Int but a State Int a, which we then bind over to get the integer out. So this ends up being equivalent to something like this (though the actual State action is more complex, and more powerful):

test = scenario do
  let (|>) = flip ($)
  let x = 0
        |> \a -> (+ 1) a
        |> \b -> (+ 1) b
        |> \c -> (+ 1) c
  x === 3

As you can see, it doesn’t really “return” in the conventional sense, but depending on what you meant by “yield”, you may be able to see that it yields a new value each time to the next operation. I don’t know if this is what you were implying by “different contexts”, but it might help, and you can potentially see how this can expand to other monad Action-based operations. For example, when performing an Update, you can have a different result based on previous fetch operations.

Long story short, DAML allows for a very restricted simulation of mutation and operation chaining which retains purity.

1 Like

Oooh, I’m loving that F# pipe operator!

I know the ampersand (&) is traditional among Haskellers, but I’ve written way too many shell scripts and I always parse a & b as “do a and b concurrently”.

There was a PR to include the pipe operator in the stdlib, but it ran into some problems with eagerness and evaluation order. Essentially, the compiler wants to be able to simplify x |> f to f x but can’t because the evaluation order would change. See @Martin_Huschenbett 's comments for detail.

1 Like