This page gives reference information on functions in Daml.
Daml is a functional language. It lets you apply functions partially and also have functions that take other functions as arguments. This page discusses these higher-order functions.
In Reference: expressions, the
tubeSurfaceArea function was defined as:
tubeSurfaceArea : Decimal -> Decimal -> Decimal tubeSurfaceArea r h = 2.0 * pi * r * h
You can define this function equivalently using lambdas, involving
\, a sequence of parameters, and an arrow
tubeSurfaceArea : BinaryDecimalFunction = \ (r : Decimal) (h : Decimal) -> 2.0 * pi * r * h
The type of the
tubeSurfaceArea function described previously, is
Decimal -> Decimal -> Decimal. An equivalent, but more instructive, way to read its type is:
Decimal -> (Decimal -> Decimal): saying that
tubeSurfaceArea is a function that takes one argument and returns another function.
tubeSurfaceArea expects one argument of type
Decimal and returns a function of type
Decimal -> Decimal. In other words, this function returns another function. Only the last application of an argument yields a non-function.
This is called currying: currying is the process of converting a function of multiple arguments to a function that takes just a single argument and returns another function. In Daml, all functions are curried.
This doesn’t affect things that much. If you use functions in the classical way (by applying them to all parameters) then there is no difference.
If you only apply a few arguments to the function, this is called partial application. The result is a function with partially defined arguments. For example:
multiplyThreeNumbers : Int -> Int -> Int -> Int multiplyThreeNumbers xx yy zz = xx * yy * zz multiplyTwoNumbersWith7 = multiplyThreeNumbers 7 multiplyWith21 = multiplyTwoNumbersWith7 3 multiplyWith18 = multiplyThreeNumbers 3 6
You could also define equivalent lambda functions:
multiplyWith18_v2 : Int -> Int multiplyWith18_v2 xx = multiplyThreeNumbers 3 6 xx
Functions are values¶
The function type can be explicitly added to the
tubeSurfaceArea function (when it is written with the lambda notation):
-- Type synonym for Decimal -> Decimal -> Decimal type BinaryDecimalFunction = Decimal -> Decimal -> Decimal pi : Decimal = 3.1415926535 tubeSurfaceArea : BinaryDecimalFunction = \ (r : Decimal) (h : Decimal) -> 2.0 * pi * r * h
tubeSurfaceArea : BinaryDecimalFunction = ... follows the same pattern as when binding values, e.g.,
pi : Decimal = 3.14159265359.
Functions have types, just like values. Which means they can be used just like normal variables. In fact, in Daml, functions are values.
This means a function can take another function as an argument. For example, define a function
applyFilter: (Int -> Int -> Bool) -> Int -> Int -> Bool which applies the first argument, a higher-order function, to the second and the third arguments to yield the result.
applyFilter (filter : Int -> Int -> Bool) (x : Int) (y : Int) = filter x y compute = scenario do assert (applyFilter (<) 3 2 == False) assert (applyFilter (/=) 3 2 == True) assert (round (2.5 : Decimal) == 3) assert (round (3.5 : Decimal) == 4) assert (explode "me" == ["m", "e"]) assert (applyFilter (\a b -> a /= b) 3 2 == True)
The Folding section looks into two useful built-in functions,
foldr, that also take a function as an argument.
Daml does not allow functions as parameters of contract templates and contract choices. However, a follow up of a choice can use built-in functions, defined at the top level or in the contract template body.
A function is parametrically polymorphic if it behaves uniformly for all types, in at least one of its type parameters. For example, you can define function composition as follows:
compose (f : b -> c) (g : a -> b) (x : a) : c = f (g x)
c are any data types. Both
compose ((+) 4) ((*) 2) 3 == 10 and
compose not ((&&) True) False evaluate to
True. Note that
((+) 4) has type
Int -> Int, whereas
not has type
Bool -> Bool.
You can find many other generic functions including this one in the Daml standard library.
Daml currently does not support generic functions for a specific set of types, such as
Decimal numbers. For example,
sum (x: a) (y: a) = x + y is undefined when
a equals the type
Party. Bounded polymorphism might be added to Daml in a later version.