Clojure – Multi-Arity and Variadic functions

In F#, you can’t over­load a let-bound func­tion, and whilst it’s a hin­drance some­times you can gen­er­al­ly work around it eas­i­ly enough since you can still over­load mem­bers of a class. All you need to do is to wrap the mod­ule and con­stituent func­tions into a class and over­load the class mem­bers instead.

Multi-Arity Functions

This is where mul­ti-ari­ty func­tions come in in Clo­jure (an ari­ty is sim­ply the num­ber of argu­ments that a func­tion can take).

One way to define mul­ti-ari­ty func­tions is to use the defn macro, for instance:

As you’ve prob­a­bly noticed, it’s pos­si­ble for one over­load to call anoth­er, so you can use this tech­nique to set default argu­ment val­ues as shown above. On its own, that’s not very inter­est­ing, and an effect that can be eas­i­ly repli­cat­ed in F# using a com­bi­na­tion of option­al para­me­ters and the built-in default­Arg func­tion with class mem­bers, even with­out resort­ing to over­load­ing (again, this is sad­ly only sup­port­ed with class mem­bers and not func­tions..).

Variadic Functions

What is def­i­nite­ly more inter­est­ing is Clo­jure’s sup­port for vari­adic func­tions – func­tions with infi­nite ari­ty.

A vari­adic func­tion has a & sym­bol in its argu­ments list, which tells the com­pil­er that the next para­me­ter col­lects all remain­ing argu­ments as a sequence. So, if we rewrite the greet func­tion to take one or more argu­ments we can end up with a vari­adic func­tion such as:

As you can see, the argu­ments “Dar­ryl”, “Deepu” and “Tom” has been packed into the argu­ment rest in the func­tion def­i­n­i­tion and print­ed as a list (Clo­jure’s lists are enclosed in paren­the­ses ( ) just like its func­tion invo­ca­tions). If you come from a .Net back­ground then this behav­iour should be famil­iar to you, because that is how para­me­ter arrays works in .Net.

So what’s so spe­cial about vari­adic func­tions in Clo­jure then?

To quote Sebas­t­ian Shaw from the excel­lent X-Men First Class film:

image

In Clo­jure, there’s a built-in apply func­tion which allows you to ‘unpack’ a sequence and pass the unpacked val­ues to a func­tion as indi­vid­ual argu­ments. With this, we can now rewrite the vari­adic ver­sion of greet as fol­lows:

Notice that the argu­ments “Dar­ryl”, “Deepu” and “Tom” are no longer treat­ed as a list but as indi­vid­ual argu­ments to the print func­tion, pret­ty neat. This SO answer also sheds some more light on why vari­adic func­tions exist in Clo­jure with some inter­est­ing exam­ples and idiomat­ic use of this type of func­tions.

 

Links

MSDN – F# Para­me­ters and Argu­ments

Clo­jure – Func­tion­al Pro­gram­ming

Clo­jure Docs – apply

SO – Why are many Clo­jure func­tions vari­adic


Clo­jure Cheat­sheet

Learn X in Y min­utes – where X = Clo­jure