About This

If all goes well, this will become a little online Clojure tutorial for the Facebook Clojure Community.

If it doesn't go well, blame me - my name is Carl Smotricz and I'm the only (so far) author.

I'm no Clojure guru. I'm an enthusiast looking to share my enthusiasm with others. Comments, suggestions, criticism, contributions are welcome.

7. More Arguments

OK, so writing functions that fiddle with a small number of arguments is pretty easy. And if you need more interesting functionality, you can simply combine functions, which you can write yourself if need be.

Let's see how this pans out when the number of arguments increases or becomes variable!

From 2 to 3

The last assignment was:

Write a function max2 that will return the larger (more positive) of two numeric arguments (a, b)!
(no need to do this again, of course).

So guess what's next?

Write a function max3 that will return the largest (most positive) of three numeric arguments (a, b, and c)!
Note: We're not bothering finding the maxes of abses this time. Just plain numeric max will do fine.
Please do this twice:

  • First time around, restrict yourself to using if, < or >, and and, as before.
  • The second time, use your previously defined function max2 ! This version, if done right, should end up quite a bit simpler than the first one.

From 3 to ... [2]

No, we're not going from 3 to 4 here. Mindlessly adding more arguments wouldn't teach any new concepts.

Sooner or later we're going to have more data than we want to provide arguments for. At that point, we'll be wanting to pass data structures rather than simple values. In Lisp, the data structure of choice is (almost always) a list. In Clojure, it's often a vector.

A first useful step in the evolution from single arguments to lists or vectors is the automatic transformation of a list of arguments into a list. This is a really cool and useful feature of Clojure. The official name is destructuring.

Here is just one of Clojure's destructuring capabilities, and it's nice and simple. It allows you to turn (part of) a list of arguments into a list. Here's how to do that:



Note that "-" is a legal (and common) character in function names! Because Lisp/Clojure functions are prefix (first thing inside the parentheses), there's never any danger of mistaking a character in a name for an operator.

The argument list now consists of the usual "a" and "b", but then there's an ampersand ("&") and "more".

What the ampersand says is: If there are any more arguments after the first two, pack them into a list and assign that list to "more".

This function isn't meant to return a useful value (it ends up returning nil). I'm using the new function println, which takes any old data element and prints it out in human-understandable form. The "ln" means to print a line feed after the data.

I've altered -main to call chew-args with a few test cases:


Here's what comes out:


So in the first case:

  • The first argument ended up in a ;
  • the second argument ended up in b ;
  • the rest of the arguments ended up as a list in more .
In the second case:
  • The first argument again ended up in a ;
  • the second argument again ended up in b ;
  • there were no more arguments, so more ended up being nil .
In the third case:
  • We gave just one argument to a function declared as having two plus optional arguments; Clojure is flexible about the optional arguments, but the explicit ones are mandatory, so we got an error message about not passing enough arguments.
Sorry about the long lecture! We're almost done, though, and ready for the next exercise.

So... if we want to be totally flexible about the number of arguments, we can take this destructuring to the extreme:


Now all our arguments end up as a list, and we can pass as few or as many as we want. 


If we pass none, more is simply nil .

Now, finally, we're ready for another rewrite of max - let's call it max0:

Write a function max0 that destructures its arguments into a list args and returns the larger of the 2 arguments. Write it to handle exactly 2 arguments correctly.
Handling other cases is a later exercise.
Hints:
  • You will want to use functions first and second .

No comments:

Post a Comment