Programming C, C++, Java, PHP, Ruby, Turing, VB
Computer Science Canada 
Programming C, C++, Java, PHP, Ruby, Turing, VB  

Username:   Password: 
 RegisterRegister   
 [Lisp-tut] Taking a format string apart
Index -> Programming, General Programming -> Functional Programming
View previous topic Printable versionDownload TopicSubscribe to this topicPrivate MessagesRefresh page View next topic
Author Message
wtd




PostPosted: 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
Sponsor
sponsor
Display posts from previous:   
   Index -> Programming, General Programming -> Functional Programming
View previous topic Tell A FriendPrintable versionDownload TopicSubscribe to this topicPrivate MessagesRefresh page View next topic

Page 1 of 1  [ 1 Posts ]
Jump to:   


Style:  
Search: