Defining Functions

Most of the time during programming is spent defining functions (or methods). In the following we will concentrate on functions, but most will be true for methods as well except for using dm instead of de.

Functions with no argument

The notorious "Hello world" function must be defined:
   : (de hello ()
      (prinl "Hello world") )
   -> hello
The '()' in the first line indicates a function without arguments. The body of the function is in the second line, consisting of a single statement. The last line is the return value of 'de', which here is the defined symbol. From now on we will omit the return values of examples when they are unimportant.

>Now you can call this function this way:
   : (hello)
   Hello world


Functions with one argument

A function with an argument might be defined this way:
   : (de hello (X)
      (prinl "Hello " X) )
   # hello redefined
PicoLisp informs you that you have just redefined the function. This might be a useful warning in case you forgot that a bound symbol with that name already existed.
   : (hello "world")
   Hello world
   : (hello "Alex")
   Hello Alex


Preventing arguments evaluation and variable number of arguments

Normally, PicoLisp evaluates the arguments before it passes them to a function:
   : (hello (+ 1 2 3))
   Hello 6
   : (setq A 1  B 2)       # Set 'A' to 1 and 'B' to 2
   -> 2
   : (de foo (X Y)         # 'foo' returns the list of its arguments
      (list X Y) )
   -> foo
   : (foo A B)             # Now call 'foo' with 'A' and 'B'
   -> (1 2)                # -> We get a list of 1 and 2, the values of 'A' and 'B'
In some cases you don't want that. For some functions (setq for example) it is better if the function gets all arguments unevaluated, and can decide for itself what to do with them.

For such cases you do not define the function with a list of parameters, but give it a single atomic parameter instead. PicoLisp will then bind all (unevaluated) arguments as a list to that parameter.
   : (de foo X
      (list (car X) (cadr X)) )        # 'foo' lists the first two arguments

   : (foo A B)                         # Now call it again
   -> (A B)                            # -> We don't get '(1 2)', but '(A B)'

   : (de foo X
      (list (car X) (eval (cadr X))) ) # Now evaluate only the second argument

   : (foo A B)
   -> (A 2)                            # -> We get '(A 2)'


Mixing evaluated arguments and variable number of unevaluated arguments

As a logical consequence, you can combine these principles. To define a function with 2 evaluated and an arbitrary number of unevaluated arguments:
   : (de foo (X Y . Z)     # Evaluate only the first two args
      (list X Y Z) )

   : (foo A B C D E)
   -> (1 2 (C D E))        # -> Get the value of 'A' and 'B' and the remaining list


Variable number of evaluated arguments

More common, in fact, is the case where you want to pass an arbitrary number of evaluated arguments to a function. For that, PicoLisp recognizes the symbol <code>@</code> as a single atomic parameter and remembers all evaluated arguments in an internal frame. This frame can then be accessed sequentially with the args, next, arg and rest functions.
   : (de foo @
      (list (next) (next)) )     # Get the first two arguments

   : (foo A B)
   -> (1 2)
Again, this can be combined:
   : (de foo (X Y . @)
      (list X Y (next) (next)) ) # 'X' and 'Y' are fixed arguments

   : (foo A B (+ 3 4) (* 3 4))
   -> (1 2 7 12)                 # All arguments are evaluated
These examples are not very useful, because the advantage of a variable number of arguments is not used. A function that prints all its evaluated numeric arguments, each on a line followed by its squared value:
   : (de foo @
      (while (args)                            # Check if there are some args left
         (println (next) (* (arg) (arg))) ) )  # Call the last arg (next) returned

   : (foo (+ 2 3) (- 7 1) 1234 (* 9 9))
   5 25
   6 36
   1234 1522756
   81 6561
   -> 6561
This next example shows the behaviour of 'args' and 'rest':
   : (de foo @
      (while (args)
         (next)
         (println (arg) (args) (rest)) ) )
   : (foo 1 2 3)
   1 T (2 3)
   2 T (3)
   3 NIL NIL
Finally, it is possible to pass all these evaluated arguments to another function, using pass:
   : (de foo @
      (pass println 9 8 7)       # First print all arguments preceded by 9, 8, 7
      (pass + 9 8 7) )           # Then add all these values

   : (foo (+ 2 3) (- 7 1) 1234 (* 9 9))
   9 8 7 5 6 1234 81             # Printing ...
   -> 1350                       # Return the result

http://picolisp.com/wiki/?tutfun

01nov10    abu