Download as docx, pdf, or txt
Download as docx, pdf, or txt
You are on page 1of 8

S cientific P rogramming

Editors: Konstantin Läufer, laufer@cs.luc.edu


Konrad Hinsen, hinsen@cnrs-orleans.fr

The Promises of Typed, Pure, and


Lazy Functional Programming: Part II
By Konstantin Läufer and George K. Thiruvathukal

This second installment picks up where Konrad Hinsen’s article “The Promises of Functional
Programming” from the July/August 2009 issue left off, covering static type inference and lazy evaluation
in functional programming languages.

I n the first installment in this series


on functional programming, Kon-rad
1
first installment, we can create a list
from some elements and then
prepend an element to that list:
but we can’t prepend an element to
an-other element

Hinsen introduced the func-tional Integer i = new Integer(4); i.add(3);


programming paradigm, which user=> (cons 3 (list 4))
encourages recursion and higher-order (3 4).
functional abstraction in algorithms. In
this second installment, we explore or
several other aspects of the functional However, we can’t prepend an
paradigm. Using examples in the Clo- element to another element List<Integer> l = new
jure, Java, and Haskell languages, we
discuss some of the benefits of static Integer(4);
typing with type inference and pure, user=> (cons 3 4) l.add(3);
side-effect-free functional program- java.lang.
ming with lazy evaluation. In particu- In the first case, the error message is
lar, we argue that these features make IllegalArgumentException: Don’t
Haskell a compelling choice for gen- know how to create ISeq from: Integer The method add(int) is un-defined for the
eral software development. The scien- type Integer, while in the second case,
tific computing community, however, it’s Type
will likely require better numeric li- because the predefined cons function
brary support and efficient functional mismatch: cannot convert from Integer to
versions of scientific algorithms before requires its second argument to be of a List<Integer>. Java’s type system
accepting Haskell more widely. list type. Clojure’s type system de- detected these errors, reported them
tected the attempt to invoke the func- while we were edit-ing or compiling
Dynamic and Static Typing tion on an argument of the wrong type, the program con-taining this code,
Type systems in programming lan- reported a type error, and stopped pro- and refused to let us run it. Java uses
guages ensure that we correctly use gram execution. Clojure uses dynamic static typing: type errors are detected
every program element according to its typing: type errors don’t get detected at compile time and programs with
type—that is, according to the abstrac- until the program executes. Other lan- type errors won’t even compile.
tion the program element represents. guages with dynamic typing include Other languages that use static typing
Typically, numeric values participate in Groovy, JavaScript, Lisp, Objective-C, include Ada, C, C++, C#, Fortran,
arithmetic operations and compari- Perl, Python, Ruby, Scheme, and Haskell, Java, ML, Pas-cal, and
sons, lists participate in element access Smalltalk. Scala. Among those, the ones that
and concatenation, and so on. Now, let’s look at the behavior of also support higher-order fea-tures
First, let’s look at type system be- Java’s type system. We can create a such as first- class functions (C#,
havior in Clojure, a modern LISP list from some elements and then Haskell, ML, and Scala) or first-class
dialect that runs on the Java Virtual prepend an element to that list objects (Ada, C#, Java, and Scala) are
Machine. As Hinsen showed in the called higher-order typed, or HOT.
List<Integer> l = Arrays. Assuming a sound type system, static
asList(4); typing represents a conservative
l.add(3); approach: a program will be allowed to

68 Copublished by the IEEE CS and the AIP 1521-9615/09/$26.00 © 2009 IEEE Computing in Science & Engineering
On Typecasting and
In this example, we mix strings and real URL objects
Conversions within the same collection. We then iterate through the

Even in typed languages such as C++, C#, and Java, we must collection and do something with the strings. We use the
instanceof operator to determine which objects are strings,
sometimes convert a numeric value from one
type to another. When going from 16-bit integer to a 32-bit cast them from type Object to the more specific type String,
integer, for example, there’s no loss of information, and it’s and do something string-specific, such as creating a URL
safe to just let the conversion happen implicitly. In the other from it. If we hadn’t used the instanceof operator, the cast
direction, however, part of the original number might get lost would have failed as soon as the iteration reached the URL
and conversion should happen only if the programmer takes instance.
responsibility. The programmer takes this responsibility Casts from a more general to a more specific type can
using a typecast—or simply, cast— construct. In the fail at runtime—as, for example, when an object isn’t of the
following Java snippet, for example, the last line would expected specific type or a more specific type. There-fore,
cause a compile-time error without the cast: we note that only programs without casts are guaran-teed
to be free of type errors at runtime. By contrast, casts in the
int i = 25; opposite direction (from a specific to a more general class)
float x = i; can never fail, so they don’t need a runtime check. Finally,
int k = (int) f; casts between unrelated classes, such as String to Integer,
can never succeed, so they always cause a compile-time
In contrast, Haskell provides such conversions using type error.
ex-plicit conversion functions. In the equivalent situation, Casting versus conversion functions was a huge sub-ject
for example, we could choose from among ceiling, floor, of debate in the C++ community back when cycles were
round, and truncate. precious and any stealth data “transformation” (no matter
There are similar situations where programmers think how trivial) could incur a substantial performance overhead.
they know far more about a certain object’s type than the (This was due to the copy-construction cascad-ing effect,
compiler could possibly know. Such a situation might arise which is no longer an issue in most modern object-oriented
with heterogeneous, predefined type collections, where languages as they typically copy refer-ences instead of
programmers are unable to define a specific common ab- values.) Today, however, casting is often a liability that
straction after the fact (another would be to define wrap- actually causes runtime typing errors—even in
pers with a common interface for the predefined types): programming languages with well-founded type systems
like Java. Worse, it’s well known (especially among
List<Object> links = seasoned C/C++ programmers such as ourselves) that not
new ArrayList<Object>(); all casts should be allowed. For example, there is a natural
links.add(“http://www.computer.org/cise”); links.add(new promo-tion of short -> int -> long -> long long (in C) that is
URL(“http://cise.aip.org/”)); //... lossless; however, the reverse transformation is unnatu-ral,
highly error-prone, and nonportable, especially in a
for (final Object o : links) heterogeneous computing world that still features 16-, 32-,
if (o instanceof String) { and 64-bit processors. Using conversion functions (instead
String s = (String) o; of casts) lets you ensure that all meaningful conversions are
URL link = new URL(s); performed correctly (forward and backward, by making all
// do something with the link down conversions explicit and precise) with only a slight
} inconvenience to the programmer (and inlining can help
alleviate most performance issues).

run only if we can guarantee that it’s checker would still reject the follow- That might seem a little restrictive;
free of type errors. Thus, a program ing program, even though the errone- dynamically typed languages would
that passes type checking is guaran- ous code would always be skipped: have no complaints about it. But sup-
teed not to fail at runtime because of pose the conditional expression is
type errors (with some restrictions, as if (3 > 4) { List<Integer> l = much more complex and evaluates to
we discuss in the sidebar “On Type- new true on some rare occasions as part of
casting and Conversions”). Because Integer(4); some mission-critical software—such
conditions aren’t evaluated until run l.add(3); as air-traffic control, Internet routers,
time, for example, the static type } and ATM machines—where every

September/October 2009 69
Scientific Programming

single line of code, reachable or not, It’s important to distinguish this from Let’s see how this works out in
must be checked before it’s embedded what happens in languages like Py- Haskell (using the Glasgow Haskell
and deployed on a large scale. With thon, where the static type of x, y, and interpreter, ghci; see www.haskell.org).
dynamic typing, disaster could ensue if z are all “object” types; the static type We start with a typed version of the
the conditional evaluated to true. (Al- of each is unknown. Only the runtime make-adder function from the first
though this example might seem im- type is known by examining type(x), installment. As we recall, makeAd-der
probable, binary patching is routinely type(y), or type(z). The C# language takes a numeric argument x and returns
used to change compiled code in a de- (from Microsoft’s .NET family) also a new function on another nu-meric
ployed system, such as for updating op- supports automatic variable typing. argument y that adds x and y:
erating systems, and many industries So, we can write the above as
use the technique to patch equipment, Prelude> let makeAdder x = \y -> x
such as telecommunications switches, var x = new Integer(4); var x = +y
that require near-zero downtime.) With new Integer(5); var z = x + y;
static typing, we’d have known about Within the interpreter, we use the
the error inside the if statement long keyword let to define new variables
before deploying the system. In the following typical example of (the keyword isn’t necessary for top-
Static typing also has a significant higher-order programming, we use level variable definitions in source
performance benefit: because the the strategy pattern to represent a files). Let’s now apply makeAdder to
compiler guarantees type safety, we custom comparison strategy as a a suitable argument:
don’t need the runtime checks found func-tion (in Java, encapsulated
in dynamically typed languages and within an object) that we pass to the Prelude> makeAdder 3 No
our code runs faster (especially when actual sort function: instance for (Show
it’s all written in the same language). (t -> t))
But statically typed languages’ safe- List<Integer> l = ...
ty comes at a price: we must declare Comparator<Integer> c = Given that applying makeAdder to a
the type of each variable in the pro- new Comparator<Integer>() { public single argument results in a new
gram, including formal arguments of int compare( Integer l, Integer r) { func-tion that expects another
methods and instance variables. This argument, it’s understandable that the
can get tedious quickly as code gets ... } interpret-er complains that it doesn’t
more complex, especially with higher- }; know how to print this (or any other)
order programming. There are, how- Collections.sort(l, c); function. Instead, let’s use the
ever, several emerging languages that interpreter’s :t (a shorthand for :type)
automatically assign types to variables. In the next section, we discuss how to command to take a look at the
For example, in the Boo language (a do away with most of this tedium. expression’s precise type:
type-safe version of Python designed
for the .NET platform), we can write Type Inference and Prelude> :t makeAdder 3
that Universal Quantification makeAdder 3 :: (Num t) =>
Wouldn’t it be nice if we could have t -> t
x = new Integer(4) y = our cake and eat it, too? That is,
new Integer(5) z = x + y couldn’t we have the safety of static This type means that the function takes
typing without its tedium? Surpris- an argument of type t and re-turns a
ingly, the answer is yes! There are result of type t, assuming that t is a
Here, x and y are both assigned the some functional languages that have numeric type. Indeed, we can ap-ply
static type of Integer (on first use) and type systems as or more powerful this function to another argument and
z is assigned the same static type (by than those of, say, Java, but that are get the expected numeric result:
inferring the expression’s result capable of figuring out the correct,
type). If y were a Float instead of intended types of variables and Prelude> (makeAdder 3) 4 7
Integer, we’d infer z to be a Float. functions in al-most all situations.

70 Computing in Science & Engineering


or simply

Prelude> makeAdder 3 4 7

Why didn’t the interpreter simply Programmers (like us) who grew support for common data structures
type the function as, say, Integer -> up on imperative programming lan- such as lists and tuples.)
Integer, especially given that we guages usually separate the param-
passed an integer constant as the first eter types from the return type in a Prelude> 3 : [4] [3,4]
argument? Let’s look at that integer typical function definition. So, the
constant’s type by itself: Haskell syntax might initially seem a
bit weird. That is, when you see an Beyond minor syntactic differ-
Prelude> :t 3 expression like a -> a -> a, your first ences, this looks just like the Clojure
3 :: (Num t) => t inclination is to think about the first example above. But a major differ-
two items between arrows, a and a, as ence is that Haskell knows the type of
Aha! What we see is that 3 can being the function’s arguments, and the : operator, equivalent to Clojure’s
have any required numeric type, so the third item, a, as being the result cons function. (Haskell supports sym-
it’s much more general than an inte- type. This is in fact correct if you bolic infix operators, which become
ger value. Typically, Haskell’s type apply the function to both argu- prefix functions when surrounded by
system deals quite naturally with the ments, but as we saw, the function parentheses.)
overloading of numeric constants and can also take its arguments one after
operators, and we don’t usually have the other. Prelude> :t (:)
to think much about it. (To handle This highlights a key differ-ence (:) :: a -> [a] -> [a]
general operator and function over- between most functional and
loading in a systematic yet unob- imperative languages. Functional In other words, this operator takes a
trusive way, Haskell uses type languages encourage higher-order value of type a and a list with
classes: a type class Num includes Int functions that curry their argu-ments elements of type a, and produces
for fixed-precision integers, Integer (after the logician Haskell B. Curry, another list of type a.
for arbitrary-precision integers, and who described this technique) . That The list’s elements can be of any type
so on. Accordingly, we can constrain is, functions are applied to some or as long as that type is used con-sistently;
the value 3 to any specific type all of their ar-guments one after the this concept is known as universal
included in the type class: other, which means that the result can quantification: it works for all types a.
be either a function or a value. These lists are homogeneous: all elements
Prelude> :t (3 :: Int) must be of the same type, so we can’t
(3 :: Int) :: Int For example, we can define the prepend, say, a number to a list of
Prelude> :t (3 :: Integer) function inc (increment by 1) by characters. (We discuss type-safe
(3 :: Integer) :: Integer partially applying the makeAdder heterogeneous lists later.)
function
The details of systematic overload- Prelude> 3 : [‘a’, ‘b’]
ing in Haskell are beyond our scope Prelude> let inc = makeAdder 1 No instance for (Num Char) arising
here, but we offer a specific example from the literal
later.) We can then increment any value as ‘3’ at <interactive>:1:0 Possible
What about the type of makeAdder follows: fix: add an
itself? instance declaration for (Num
Prelude> inc 4 Char)
Prelude> :t makeAdder makeAdder :: 5
(Num a) => a -> As above, we can’t prepend an
a -> a Coming back to our list example, element to another element:
we can create a list from some ele-
ments and then prepend an element to Prelude> 3 : 4
that list. (Similar to modern scripting No instance for (Num [t]) arising
languages such as Python, functional from the literal ‘4’ at
languages typically offer syntactic <interactive>:1:4

September/October 2009 71
Scientific Programming

Possible fix: add an instance Here is the whole story, step by step: and practice, typed functional pro-
declaration for (Num [t]) gramming languages compile well, and
Prelude> countdown 5 the same compilation techniques work
==> (reverse . (flip take [0 well with imperative languages like
These error messages say that it ..]) . (+ 1)) 5 Java. Clean, OCaml, and F# of-fer
found some numeric value instead of ==> reverse (flip take [0 ..] (1 + 5)) other, modern examples. Another
either a character value or a list advantage could become even more
value. If we narrow value 4’s type ==> reverse (flip take [0 ..] 6) prominent in the multicore and novel
down from a general number to a computing era: if multiple expressions
fixed-precision integer of type Int, ==> reverse (take 6 [0 ..]) ==> reverse are ready to be evaluated, you can
then the message becomes clearer: [0,1,2,3,4,5] ==> [5,4,3,2,1,0] throw any number of cores at them.
With referential transparency, it’s
Prelude> 3 : (4 :: Int) Couldn’t possible to delay the evaluation of a
match expected Of course, any sane Haskell program- complex expression’s subexpressions
type ‘[t]’ against inferred mer would simply write until it’s required for computing the
type ‘Int’ final top -level result. This evaluation
In the second argument of ‘(:)’, Prelude> let countdown n = reverse strategy is called lazy evaluation—as
namely ‘(4 :: Int)’ [0 .. n] opposed to the more familiar eager
evaluation—where all subexpressions
Pure Functional Programming are evaluated inside-out, regardless of
As a rather contrived example of and Lazy Evaluation whether they matter for the final re-
higher-order typed programming, Pure functional languages such as sult. We can think about lazy evalu-
we’ll use a Haskell version of the Haskell are side-effect free, except ation as a generalization of Boolean
countdown method from Hinsen’s within special language constructs for short-circuit evaluation, but without the
article, put together from predefined actions, such as input/output, that by pitfalls of missing skipped subex-
Haskell methods without recursion or definition entail side effects. The pressions’ side effects.
even a formal argument: absence of side effects guarantees ref- Lazy evaluation generally leads to
erential transparency: we can replace the inevitable overhead of keeping
Prelude> let countdown = reverse . any expression in a program with its track of computations that are ready to
(flip take [0 resulting value without changing the be evaluated but haven’t been required
..]) . (+ 1) program’s meaning. This makes it yet. Consequently, the memory foot-
possible to reason about programs and print of programs in lazy languages
This terse definition deserves a bit their correctness, similar to the way should be higher than equivalent pro-
of an explanation: we’d reason about mathematical grams in eager languages. Data from
formulas. In practice, this means that the Computer Languages Benchmarks
• the dot operator performs function every variable is defined exactly once Game (http://shootout.alioth.debian.
composition; and can’t be modified later. org/) confirms this expectation. Nev-
• + 1 is the partial application of ad- Although side effects are common in ertheless, the Glasgow Haskell Com-
dition to 1, so it adds one to the other many modern scientific and high- piler now produces such effectively
argument it receives (once performance computing codes, mini- optimized code that those same bench-
countdown is applied to an actual mizing side effects actually makes marks run within a factor of at most
argument); work easier for the compiler, espe- three of equivalent C and Fortran pro-
grams, and even up to three times faster
• [0 ..] is an (infinite!) list of non- cially for parallel-language compilers.
in some cases. Recent work on Haskell
negative integers; Because compilers have a notoriously
runtime support on multicore hardware
• take takes only a given number of difficult time with side effects, we can’t
2
elements of a list, so it makes the in- use many optimization techniques— has shown promising initial results. As
finite list finite; and such as common-subexpression elimi- we’ve already seen, lazy evaluation
• reverse does the expected. nation or invariant hoisting. In theory gives us the seemingly magic ability

72 Computing in Science & Engineering


to express infinite structures such as
[0 ..] naturally and concisely. By con-
trast, in conventional languages with
eager evaluation, we might represent
infinite structures by wrapping the
de-layed computation within a
function or method. For example, in
Java, we can express infinite lists of IntOrStrings. Functions on data-types t2 = Node “Hello” [ Node
using the Iterator abstraction: usually employ pattern matching to “World” []
perform the case distinction among the ]
class Naturals implements possible variants and to bind sub-
Iterator<Integer> { private int value structures to variables: However, we can’t yet print values
= 0; of these types:
public boolean hasNext() { return add [] = (0,””)
true; } add (AnInt i : xs) = Prelude> t1
public Integer next() { return let (k, t) = add xs in (i + k, t) No instance for (Show (Tree
value++; } Integer))
} add (AString s : xs) =
To solve this problem, we use
let (k, t) = add xs in (k, s ++ t)
Haskell’s systematic overloading
mechanism to define the missing show
function used by the interpreter’s main
Prelude> add [AnInt 3,
AString “adsf”, loop to print values:
AnInt 7, AString “qwer”]
(10,”adsfqwer”) instance (Show a) => Show (Tree
a) where
We can take this idea further and This list is homogeneous in the show Empty = “Empty” show
develop a full-fledged library for pro- sense that all of its elements are of (Node x ts) = “Node “ ++ (show
x) ++
gramming with infinite streams, as type IntOrString, but heteroge-neous
“ “ ++ (show ts)
others have already done for various in the sense that IntOrString is a
languages. The lucid functional data- discriminated union type. This instance definition means that
flow language by Edward Ashcroft and Things get more exciting and useful
we can print a type a tree as long as we
William Wadge is an early example of when we introduce recursion; here’s a
already know how to print a. Haskell
streams and infinitary programming.
3 very simple yet general tree type: already knows how to print its pre-
defined basic types, such as Integer, so
Algebraic Datatypes data Tree a = Empty
we can print our tree exactly the way
Returning to our types discussion, al- | Node a [Tree a]
we originally coded it:
gebraic datatypes let us define our own
nonrecursive and recursive structures. This definition says that a tree is Prelude> t1
Formally speaking, an algebraic data-type either empty or is a node containing a Node 1 [Node 2 [Node 4
is a (possibly recursive) sum type of value of some arbitrary type a and a []],Node 3 [Node 5 []]]
product types; sum and product types are list of children, which are also trees
formalizations of union and record/ tuple and whose values, if any, are also of We can now define some typical tree
types, respectively (see http://blog. type a. We can now define trees of functions. The pattern underscore is
lab49.com/archives/3011 for more de- any type as long as that type is used a pseudo-variable for substructures
tails). As a simple nonrecursive example, consistently within a specific tree. that we don’t need to reference on the
we define a datatype representing the right-hand side. The type declarations
union of integers and strings as t1 = Node 1 [ are optional, but often helpful for
Node 2 [ doc-umenting intent and usage: we’ll
data IntOrString = AnInt Int | AString Node 4 [] get an error if our implementation
String ], doesn’t match our stated intent:
Node 3 [
We then define a function that adds Node 5 [] size Empty = 0
all the integers and concat-enates all ] size (Node _ ts) = foldl (+)
the strings it finds in a list ] 1 (map size ts)

September/October 2009 73
Scientific Programming

rootValue :: Tree a -> a differently. In this new version, the the second case, addAll is list concat-
rootValue (Node x _) = x first argument is the list represent-ing enation with the order of arguments
the work queue, and the second flipped, so that the children get added
traverse :: Tree a -> [Tree a] traverse argument is a function for adding to the queue’s beginning, and we have
Empty = [] traverse (t @ (Node x ts)) = another list of elements to the queue; our last-in-first-out discipline back, re-
this function determines the order in sulting in a depth-first tree traversal.
t : concat (map traverse ts) which we traverse the tree’s subtrees: While we pass a queue representa-tion
and an associated operation openly to the
In these functions, map applies a traverseUsingList [] _ = [] traverseUsingList function, we could
function to each element in a list (in traverseUsingList (Empty : instead define a proper ab-stract datatype
this case, it recursively applies size to rest) addAll = for queues in two ways: through a tuple
the children, ts), while concat flat-tens traverseUsingList rest of one or more functions that share and
a list of lists to a simple list. Tree addAll operate on a hidden data representation,
traversal converts a (nonlinear) tree traverseUsingList or through a nonstan-dard extension that
to a linear sequence of references to ((t @ (Node x ts)) : rest) provides existential quantification of type
all of the tree’s subtrees. As a result, addAll = variables (in con-trast to universal
we no longer need a dedicated size t : traverseUsingList (addAll rest quantification).
func-tion because a tree’s size is ts) addAll
simply the length of its linearization:

Prelude> rootValue t1 1
We now have a functional version
of the usual tree traversal algorithm. I n this second installment on func-
Initially, the only subtree in the work tional programming, we’ve expand-ed
Prelude> size t1 5 queue is the tree itself. We then re- on the HOT languages notion and
peatedly take the first subtree from presented a case that having at least a
basic knowledge of such languages can
Prelude> traverse t1 [Node 1 the work queue, add it to the result- be part of a healthy programming diet.
[...],Node 2 [...],Node 4 [...], ing linear structure, and add the cur- Even if you’re not intent on us-ing
rent subtree’s children to the work functional programming anytime soon,
Node 3 [...],Node 5 [...]] Prelude> queue. Given that our trees are finite, the approach can help you get better
map rootValue this process continues until the work results in any language, be-cause many
(traverse t1) queue is empty. We can now invoke functional programming ideas are used
[1,2,4,3,5] this function using two different strat- to implement optimiz-ing compilers.
Also, many languages in one form or
Prelude> (length . traverse) t1 egies to add items to the work queue:
another (such as C#) are introducing
the ideas, and Micro-soft recently
5 Prelude> map rootValue introduced a completely functional
(traverseUsingList [t1] programming language, F#, into its
A limitation of our traverse function (++)) languages suite. Given that Microsoft’s
is that the traversal order is hard- [1,2,3,4,5] in the business of selling languages and
coded: the function performs a depth- Prelude> map rootValue tools, this is a big deal. We’re equally
first tree traversal, descend-ing as far (traverseUsingList [t1] convinced that clearly understanding
down the leftmost path as possible (flip (++))) typing systems can be helpful when
writing programs and avoiding the
before visiting the rest of the tree. [1,2,4,3,5]
pitfalls entailed when the decision is
This is typical for recursive im- entirely left up to runtime. Our
plementations of tree traversal, where In the first case, addAll is standard intention, however, is not to dis-miss
the implicit function-call stack serves list concatenation, the current sub- languages lacking well-founded type
as a last-in-first-out work queue that tree’s children are appended to the end systems outright. We all use a vari-ety
stores the children yet to be visited. of the queue—amounting to a first-in- of languages in our work (Java, C#,
We can make this function more first-out discipline—and the result is a
flexible by parameterizing it breadth-first traversal of the tree. In

74 Computing in Science & Engineering


Inofficial
addition to www.haskell.org, the
Haskell 101 Haskell community wiki, we
found the following resources quite
useful:
• At the 2008 Object-Oriented Programming, Systems, Languages, and Appli-
cations (Oopsla) Conference, Mark Dominus, a leading Perl developer, gave an
invited talk on the Haskell Type system. You can read his notes (and find a link to
his slides) at http://blog.plover.com/talk/atypical-typing.html.
• The Learn You a Haskell for Great Good site offers a gentle Haskell tutorial at
http://learnyouahaskell.com/chapters.
• In November 2008, O’Reilly published the first edition of Real World Haskell by
Multicore Haskell,” Proc. 14th ACM
Bryan O’Sullivan, Don Stewart, and John Goerzen. They’ve since created a Website
Sigplan Int’l Conf. Functional Program-
with freely available content at http://book.realworldhaskell.org.
ming, ACM Press, 2009 (forthcoming);
www.haskell.org/~simonmar/papers/
multicore-ghc.pdf.
3. W. Wadge and E. Ashcroft, Lucid, the
Dataflow Programming Language,
Academic Press, 1985, p. 310.

C/C++, Python) for reasons sometimes syntax does matter: Haskell’s intuitive, Konstantin Läufer is a professor of com-
beyond our control or for value beyond concise, and adaptable syntax should puter science at Loyola University Chicago.
the language (such as the ecosystem). make mathematically inclined program- His research interests include programming
Haskell itself has long been an mers feel right at home and is particular- languages, software architecture and frame-
excellent choice for general software ly effective for creating domain-specific works, distributed systems, mobile and
development, though its use in scientific languages. If you’d like to learn more, the embedded computing, human-computer
and high-performance computing has links in the “Haskell 101” sidebar will interaction, and educational technology.
been hindered by a lack of library support bring you up to speed. Läufer has a PhD in computer science from
and absence of efficient, purely func- the Courant Institute at New York University.
tional versions of common scientific Acknowledgments Contact him via www.cs.luc.edu/laufer.
algorithms. Nevertheless, Haskell has a Thanks to Konrad Hinsen for his ex-
large, vibrant, diverse community that has cellent comments on various iterations George K. Thiruvathukal is an associate
created an ecosystem ranging from a of this article and to Sergio Fanchiotti professor of computer science at Loyola
distributed version-control system for his helpful suggestions on useful University Chicago and is now an associate
(DARCS) to the HAppS Web frame-work Haskell resources. editor in chief of this magazine. His tech-nical
to the Haskore computer music system. interests include parallel/distributed systems,
The Glasgow Haskell Com-piler is very References programming language design/
mature and produces highly optimized, 1. K. Hinsen, “The Promises of Functional implementation, and computer science
fast-running code (it also supports Programming,” Computing in Science & Eng., across the disciplines. Thiruvathukal has a
separate compilation through Haskell’s vol. 11, no. 4, 2009, pp. 86–90. PhD in computer science from the Illinois
relatively simple module sys-tem). The 2. S. Marlow, S. Peyton Jones, and S. Singh, Institute of Technology. Contact him via
Haskell folks have shown that “Runtime Support for http://gkt.etl.luc.edu.

Call for Papers | General Interest


I EEE Micro seeks general-interest submissions
publication in upcoming issues. These works
for
ization. Summaries of work in progress and de-
scriptions of recently completed works are most
should discuss the design, performance, welcome, as are tutorials. Micro does not
or application of microcomputer and micropro- accept previously published material.
cessor systems. Of special interest are articles on
performance evaluation and workload character- Check our author center (www.computer.org/mc/
mi cro/author.htm) for word, figure, and reference
limits. All submissions pass through peer review
consistent with other professional-level technical
publications, and editing for clarity, readability, and
conciseness. Contact IEEE Micro at micro-ma@
computer.org with any questions.

September/October 2009 75

You might also like