-
Notifications
You must be signed in to change notification settings - Fork 4
Printing
In the previous section we developed a data structure capable of holding Lisp's abstract syntax trees (a famous Lisp list). One common task all Lisp interpreters are able to perform is to print out this data structure. Haskell has an alternative to Java's toString, a polymorphic function show. By default, show will normally print out the values the way you type them in Haskell source code (which makes it far more useful than toString, but we won't get into that). Java's toString does something similar. Both of these implementations aren't very useful to us because we need our interpreter to print the data structure out via s-expressions. Therefore, we must customize this functionality. In Haskell we can do it like this:
instance Show Expr where
show (BlaiseInt x) = show x
show (BlaiseSymbol x) = x
show (BlaiseFn x) = "<function>"
show (BlaiseList x) = "(" ++ unwords (map show x) ++ ")"
Don't let the word instance throw you off - the code above has nothing to do with instances in a conventional object oriented sense of the word. Instead, it tells Haskell that Expr "implements" a Show "interface". This allows anyone to call show on our data structure and it will print in out as an s-expression. The code above uses pattern matching - the function show is defined four times. When show is called, Haskell runtime will examine available definitions and will call appropriate one depending on which "form" of expression it's dealing with. This is similar to Java's virtual functions but a lot more powerful. In Java we can define four versions of toString and the runtime will call the correct one depending on the instance type. However, Haskell pattern matching can match on far more than the type - it can also match on values, boolean expressions (using guards), particular structures, etc. The tremendous benefit of this technique will become more apparent later. For now, let's try to implement a subset of this code in Java: a toString method to render a list.
String toString() {
StringBuffer output("(");
Iterator it = _value.iterator();
if(it.hasNext()) {
Expr value = (Expr) it.next();
output.append(value.toString());
}
for (; it.hasNext(); ) {
output.append(" ");
Expr value = (Expr) it.next();
output.append(value.toString());
}
output.append(")");
return output.toString();
}
Yet another Haskell one-liner turned into sixteen lines of Java code. In isolation such examples mean little but once you run into them again and again and again you can see an interesting picture start to emerge.