What is the use of `forall`?

What is forall used for? Could you give me an example of where you’d want to use forall?

5 Likes

DAML inherits a lot of its type system form Haskell and as such you can find a lot of quality explainers for questions like that. Eg https://wiki.haskell.org/Scoped_type_variables

In short, it allows you to explicitly tell the compiler about type variables. Take as an example the exerciseByKey function:

-- | Exercise a choice on the contract associated with the given key.
--
-- You must pass the `t` using an explicit type application. For
-- instance, if you want to exercise a choice `Withdraw` on a contract of
-- template `Account` given by its key `k`, you must call
-- `exerciseByKey @Account k Withdraw`.
exerciseByKey : forall t k c r. (HasFetchByKey t k, HasExercise t c r) => k -> c -> Update r
exerciseByKey k c = do
    (cid, _) <- fetchByKey @t k
    exercise cid c

The template type t doesn’t occur anywhere in the signature k -> c -> Update r, but you have to use it in the type constraints (HasFetchByKey t k, HasExercise t c r). To be able to do so, you first have to explicitly tell the compiler about the type variables in use: forall t k c r.

Usually when you need to do this, you’ll run into other problems like “Ambiguous Types”. But fortunately the DAML IDE will tell you how to fix that.

5 Likes

@bernhard described one of the reasons (the keyword if you want more information for that is ScopedTypeVariables). That one is related to the internal implementation of a function.

There is a second one related to the API you expose to users of a definition: The order of type variables.

You might think this doesn’t matter at first. However, as soon as you have an explicit type application (that’s what the @ sign is used for) the order becomes relevant. You can see an example of this in @bernhard’s code above:

fetchByKey @t k

fetchByKey has type TemplateKey t k => k -> Update (ContractId t, t). There are two possible orders of type variables, either the template type comes first or the key type comes first. Depending on how you order them fetchByKey @t k will use t as the template type or as the key type. The default order you get by the compiler if you do not use a forall is somewhat arbitrary (it’s deterministic and there are rules but it’s non-obvious). If you use a forall, you can control the order of type variables explicitly and make sure that t comes before k.

6 Likes

Makes sense, thanks @bernhard and @cocreature!