Functions



We'll start by defining our functions and learning what we can do with parameters.


( defun ourfunction ( arg1 arg2 arg3 )
( list arg1 arg2 arg3 )
)

As we can see, defun expects a name and a list of arguments.

Once we supply the list of arguments ( can be an empty list ) we start with the body of this function, and the last statement will be the return value of this function.

In this case we are only returning a list with the arguments received with the function.

So, once defined this function we can start using it as it if were a built-in one.


( ourfunction 1 2 3 )
;; Will return a list with the numbers we supplied


We can perform any operation in the body of our functions and they'll return the last expression executed.

( defun other-function ( a b c )
( + a b c )
)


So when called, the function will expect 3 arguments and it will return the result of the sum of those arguments.


( other-function 1 2 3 )
;; Will return the number 6


We can have optional arguments, and even put a default value for those arguments. If we wanted to check whether an optional argument is supplied or it received it's default value, we could too.


( defun a-function ( arg1 &optional arg2 arg3 )
( list arg1 arg2 arg3)
)
;; In this case our function will return nil if arg2 or arg3 are not present

( a-function 2 3 )
;; Will return a list with ( 2 3 nil )
( a-function 1 )
;; Will return a list with ( 1 nil nil )

;; To put a default value in our arguments for when are not supplied it's easy

( defun another-function ( arg1 &optional ( arg2 24 ) ( arg3 30 ) )
( list arg1 arg2 arg3 )
)

( another-function 1 )
;; Will return a list with ( 1 24 30 ) because arg2 and arg3 weren't present, but we assigned a default value

( another-function 1 2 3 )
;; Will return a list with ( 1 2 3 ) because when we supply the arguments they'll take the new value instead of the default one.

;; Now to check whether an optional value is supplied or not, we just add a variable

( defun fun-name ( arg1 &optional ( arg2 24 arg2-supplied ) ( arg3 30 arg3-supplied ) )
( list arg1 arg2 arg3 arg2-supplied arg3-supplied )
)

;; So if we are not using the optional arguments in this function, they'll have the default value and arg2-supplied and arg3-supplied will be nil ( false )

( fun-name 1 )
;; Will return a list with ( 1 24 30 nil nil )

( fun-name 1 2 3 )
;; Will return a list with ( 1 2 3 t t ) because we applied the values



So now we know how to add optional arguments, assign default values to them and check whether they are supplied or not by using other variables.

Note that we don't need to expect any argument, and even the first argument can be optional.


( defun our-shit-function ()
( + 1 2 3 )
)
;; This function does not need any argument so we will call it with just its name

( our-shit-function )
;; Will return 6

( defun optional-function ( &optional arg1 )
( list arg1 )
)

( optional-function 1 )
;; Will return 1

( optional-function )
;; Will return nil, because we didn't specified any default value

;; Also we cannot check whether the optional value is supplied with the other variable ( like the arg1-supplied ) if we
;; are not assigning a default value before

;; So this function WON'T WORK

( defun broken-function ( &optional ( arg1 arg1-supplied ) )
( list arg1 arg1-supplied)
)

;; This function is broken because arg1-supplied needs to have a default value

;; So the function will work if we define it this way

( defun repaired-function ( &optional ( arg1 30 arg1-supplied ) )
( list arg1 arg1-supplied )
)
;; This will work because we added a default value
( repaired-function 1 )
;; Will return ( 1 t )

(repaired-function )
;; Will return (30 nil )


Hope this was easy to understand. Now we'll learn about the &key arguments.

Keyword arguments work in a similar way as optional arguments do.

Instead of &optional we'll put &key

Keyword arguments are optional, they can have an assigned default value, and we can use another variable to check if they are using therir default value or not.

So the broken-function we made before, won't work either.

( defun key-fun ( &key arg1 )
( list arg1 )
)
;; Nothing special at this moment, just the &key instead of &optional.

;; Now calling this function without arguments will return nil, because arg1 is optional and has no assigned value

( key-fun )
;; Will return nil

;; But we can add a value using the keyword. Keywords are accessed by its name preceded with a colon :

( key-fun :arg1 20 )
;; Will return 20

;; But in this case, we cannot just put the value without refering to 1 first.

;; So this call WON'T WORK

( key-fun 20 )

;; Will fail, because it does not know where to put this number

( defun multi-key-fun ( &key arg1 arg2 arg3 )
( list arg1 arg2 arg3 )
)

;; Note that the colons are only when calling the function, not in its body.

( multi-key-fun )
;; Will return ( nil nil nil )

( multi-key-fun :arg1 24 :arg2 30 :arg3 50 )
;; Will return (24 30 50)

;; Now we will add default values and other variables to check whether they have the default value or not

( defun fun-with-defaults ( &key ( arg1 30 arg1-supplied ) ( arg2 34 arg2-supplied ) ( arg3 41 arg3-supplied ) )
( list arg1 arg2 arg3 arg1-supplied arg2-supplied arg3-supplied )
)
;; Now if we call it with no arguments...

( fun-with-defaults )
;; Will return (30 34 41 NIL NIL NIL) because we gave nothing, so it uses default values and check-variables are nil

(fun-with-defaults :arg1 3421)
;; Will return (3421 34 41 T NIL NIL)

(fun-with-defaults :arg1 3421 :arg2 1 :arg3 2 )
;; Will return (3421 1 2 T T T)


Note that we can mix normal arguments, &optional arguments and &key arguments

( defun mixed ( arg1 &optional ( arg2 30 arg2-supplied ) &key ( arg3 24 arg3-supplied ) )
( list arg1 arg2 arg3 arg2-supplied arg3-supplied )
)
;; In this case, at least the first argument needs to be present.
;; Once we use &key &optional, or other alternatives, the following variables will be optional, keywords, or whatever we use.

( mixed 3 )
;; Will return (3 30 24 NIL NIL)


;; As a warning, in this function we cannot omit the arg2 if we want to assign the arg3 even arg2 being optional

;; Also we cannot put &key first and &optional later

;; So this WON'T WORK

( defun mixed2 ( &key ( arg1 30 arg1-supplied ) ( arg2 1 arg2-supplied) &optional ( arg3 40 arg3-supplied) )
( list arg1 arg2 arg3 arg1-supplied arg2-supplied arg3-supplied )
)

;; We are not allowed to do that

;; The last thing, we can put another argument as a default value for another

( defun samevalues ( arg1 &optional ( arg2 arg1 arg2-set ) )
(list arg1 arg2 arg2-set )
)

;; If we only put the first argument value, arg2 will have the same value as arg1

( samevalues 24 )
;; Will return ( 24 24 nil )

( samevalues 24 21 )
;; Will return ( 24 21 t )