Reference: functions¶
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.
Defining 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 ->
as:
tubeSurfaceArea : BinaryDecimalFunction =
\ (r : Decimal) (h : Decimal) -> 2.0 * pi * r * h
Partial application¶
The type of the tubeSurfaceArea
function described previously, is Decimal -> Decimal -> Decimal
. An equivalent, but more instructive, way to read its type is: Decmial -> (Decimal -> Decimal)
: saying that tubeSurfaceArea
is a function that takes one argument and returns another function.
So 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
Note that 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, foldl
and foldr
, that also take a function as an argument.
Note
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.
Generic functions¶
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)
where a
, b
, and 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.
Note
DAML currently does not support generic functions for a specific set of types, such as Int
and 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.