[Lisp-tut] Taking a format string apart
Author |
Message |
wtd
|
Posted: Thu Feb 02, 2006 6:31 pm Post subject: [Lisp-tut] Taking a format string apart |
|
|
Taking a format string apart
First let's take a look at the format string in action.
code: | [1]> (format nil
"~{~#[~;~A~;~A and ~A~:;~@{~A~#[~;, and ~:;, ~]~}~]~}"
'(1 2 3 4))
"1, 2, 3, and 4"
[2]> (format nil
"~{~#[~;~A~;~A and ~A~:;~@{~A~#[~;, and ~:;, ~]~}~]~}"
'(1 2))
"1 and 2" |
Terror is understandable
That's one frighteningly complex string, isn't it?
The key, though is quite simple. You merely have to break it down into smaller pieces that are easier to understand.
Basics
The tilde (~) introduces a format directive.
The simplest of these is ~A, which can represent anything.
The ~{ and ~} directives deal with looping and ~[ and ~] deal with conditions.
So... what's going on in that string?
The outer directives are ~{ and ~}. This takes a list and iterates over it. The enclosed directives are evaluated for that list.
Next we have ~#[ and ~] directives. This is a variant on the conditional directive. The # indicates that it considers the number of items left. Each clause in the conditional is separated by ~;, and the default clause is indicated by the ~:; directive.
Let's look at the clauses.
The first is empty. This is what we'll output if there is nothing in the list.
The next deals with a list with a single item. Here we just have ~A, so we're just outputting that element.
The third deals with there being two elements. Here we use "~A and ~A" to output those two elements joined by "and".
The final clause
This one is decidely less simple than the previous three, and yet, not beyond our understanding.
code: | ~@{~A~#[~;, and ~:;, ~]~} |
The outer ~@{ and ~} directives are again an iteration construct. The @ symbol added in means that it will iterate over anything left. In this case, that means it will iterate over the list the outer iteration directives grabbed. It's iterating over 1, 2, 3, and 4.
Within these directives we first output a single item. Then we have a conditional which decides what should follow that item.
If zero items are left, then output nothing.
If only one item is left, output ", and".
And if there are two or more items left, the separator is a comma and a space.
Why? Why? WHY?!
Why should we subject ourselves to such unspeakable horrors?
Surely there must be a more readable way to express this logic.
code: | class Array
def join_as_english_list
case length
when 0
""
when 1
first.to_s
when 2
"#{first} and #{last}"
else
"#{self[0...-1].join(", ")}, and #{last}"
end
end
end |
Now, in all honesty, that's not so bad, but then again, Ruby's pretty expressive.
It's still a fair amount of code to delve through, and it hides some of its complexities in library methods that must be understood to fully appreciate what this new method is doing.
Is this really more readable then, if a programmer can recognize the individual components of the format string? |
|
|
|
|
|
Sponsor Sponsor
|
|
|
|
|