This article is part of a series describing a port of the samples from Practical Common Lisp (PCL) to Clojure. You will probably want to read the intro first.
This article covers Chapter 5, Functions.
One of the cool things about Common Lisp is the variety of ways to pass arguments to functions. You can pass arguments
Clojure provides many of the same things, but the syntax is different. Here is a function that takes two required arguments, and two optional arguments.
Here are some examples of calling
You can also pass values by name, using a map literal. The function
bar expects named arguments
:or clause specifies a default for
Examples of calling
Another nicety is defining an optional parameter's default value in terms of another parameter. Here is a Clojure approach that defaults
width when creating a rectangle:
Common Lisp also supports discovering whether a user specified a parameter. This comes in handy if you want to detect that the user re-specified the default for some parameter. I didn't find a built-in way to do this in Clojure. Here is one approach:
:as :all collects the entire arguments list into
all. Then, I use
contains? to detect whether the user specified a value for
If you wanted to make this feel more like Common Lisp, you could write a macro.
Common Lisp also supports a
return-from macro to "return" from the middle of a function. This encourages an imperative style of programming, which Clojure discourages.
However, you can solve the same problems in a different way. Here is the
return-from example, rewritten in a functional style so that no
return-from is needed:
apply, PCL uses a function to plot a histogram. Clojure provides an equivalent
apply. The PCL version of
plot also uses CL's
loop. Instead, I will use
dotimes for looping:
_ is idiomatic for "I don't plan to use this value". In this case I want to do something n times, but the individual iterations do not need to know their ordinal.
plot in place, we can plot any function of one argument, over any range. (The usefulness of this is sharply limited by the horizontal resolution of your output device). Some examples:
user=> (plot #(Math/pow % 2) 1 5 1) * **** ********* **************** user=> (plot identity 2 10 2) ** **** ****** ********
No big surprises here. Function invocation is flexible and powerful in Clojure.
The sample code is available at http://github.com/stuarthalloway/practical-cl-clojure.