Loyola University Chicago Loyola eCommons

Computer Science: Faculty Publications and Other Works Faculty Publications

9-2009

Scientific Programming: The Promises of Typed, Pure, and Lazy : Part II

Konstantin Läufer Loyola University Chicago, [email protected]

George . Thiruvathukal Loyola University Chicago, [email protected]

Follow this and additional works at: https://ecommons.luc.edu/cs_facpubs

Part of the Computer Sciences Commons

Recommended Citation K. Laufer and G. K. Thiruvathukal, "Scientific Programming: The Promises of Typed, Pure, and Lazy Functional Programming: Part II," in Computing in Science & Engineering, vol. 11, no. 5, pp. 68-75, Sept.- Oct. 2009. doi: 10.1109/MCSE.2009.147

This Article is brought to you for free and open access by the Faculty Publications at Loyola eCommons. It has been accepted for inclusion in : Faculty Publications and Other Works by an authorized administrator of Loyola eCommons. For more information, please contact [email protected].

This work is licensed under a Creative Commons Attribution-Noncommercial-No Derivative Works 3.0 License. Copyright © 2009 Konstantin Läufer and George K. Thiruvathuka S cientific P rogramming

Editors: Konstantin Läufer, [email protected] Konrad Hinsen, [email protected]

Th e Pr o m i s e s o f Ty p e , Pu e , a n d La z y Fu n i o n a l Pr o g r a m m i n g : Pa r t 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 and in functional programming languages.

n the first installment in this series first installment,1 we can create a list but we can’t prepend an element to an- on functional programming, Kon- from some elements and then prepend other element Irad Hinsen introduced the func- an element to that list: tional , which Integer i = new Integer(4); encourages and higher-order user=> ( 3 (list 4)) i.add(3); functional abstraction in . (3 4). In this second installment, we explore or several other aspects of the functional However, we can’t prepend an element paradigm. Using examples in the Clo- to another element List l = new jure, , and Haskell languages, we Integer(4); discuss some of the benefits of static user=> (cons 3 4) l.add(3); typing with type inference and pure, java.lang. side-effect-free functional program- IllegalArgumentException: In the first case, the error message ming with lazy evaluation. In particu- Don’t know how to create ISeq is The method add(int) is un- lar, we argue that these features make from: Integer defined for the type Integer, Haskell a compelling choice for gen- while in the second case, it’s Type eral . The scien- because the predefined cons mismatch: cannot convert from tific computing community, however, requires its second argument to be of a Integer to List. Java’s will likely require better numeric li- list type. ’s de- type system detected these errors, brary support and efficient functional tected the attempt to invoke the func- reported them while we were edit- versions of scientific algorithms before tion on an argument of the wrong type, ing or compiling the program con- accepting Haskell more widely. reported a type error, and stopped pro- taining this code, and refused to let gram execution. Clojure uses dynamic us run it. Java uses static typing: type Dynamic and Static Typing typing: type errors don’t get detected errors are detected at compile time Type systems in programming lan- until the program executes. Other lan- and programs with type errors won’t guages ensure that we correctly use guages with dynamic typing include even compile. Other languages that every program element according to its Groovy, JavaScript, Lisp, Objective- use static typing include Ada, C, C++, type—that is, according to the abstrac- C, , Python, Ruby, Scheme, and C#, , Haskell, Java, ML, Pas- tion the program element represents. . cal, and Scala. Among those, the ones Typically, numeric values participate Now, let’s look at the behavior of that also support higher-order fea- in arithmetic operations and compari- Java’s type system. We can create a list tures such as first-class functions (C#, sons, lists participate in element access from some elements and then prepend Haskell, ML, and Scala) or first-class and concatenation, and so on. an element to that list objects (Ada, C#, Java, and Scala) are First, let’s look at type system be- called higher-order typed, or HOT. havior in Clojure, a modern LISP List l = Arrays. Assuming a sound type system, dialect that runs on the Java Virtual asList(4); static typing represents a conservative Machine. As Hinsen showed in the 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 Co m p u t i n g in Sc i e n c e & En g i n e e r i n g On Ty p e c a s t i n g a n d In this example, we mix strings and real URL objects Co n v e r s i o n s within the same collection. We then iterate through the collection and do something with the strings. We use the ven in typed languages such as C++, C#, and Java, we instanceof operator to determine which objects are Emust sometimes convert a numeric from one strings, cast them from type Object to the more specific type to another. When going from 16-bit integer to a type String, and do something string-specific, such as 32-bit integer, for example, there’s no loss of information, creating a URL from it. If we hadn’t used the instanceof and it’s safe to just let the conversion happen implicitly. In operator, the cast would have failed as soon as the iteration the other direction, however, part of the original number reached the URL instance. might get lost and conversion should happen only if the Casts from a more general to a more specific type can programmer takes responsibility. The programmer takes fail at runtime—as, for example, when an object isn’t of this responsibility using a typecast—or simply, cast— the expected specific type or a more specific type.T here- construct. In the following Java , for example, the fore, we note that only programs without casts are guaran- last line would cause a compile-time error without the cast: teed to be free of type errors at runtime. By contrast, casts in the opposite direction (from a specific to a more general int i = 25; class) can never fail, so they don’t need a runtime check. float x = i; Finally, casts between unrelated classes, such as String int k = (int) f; to Integer, can never succeed, so they always cause a compile-time type error. In contrast, Haskell provides such conversions using ex- Casting versus conversion functions was a huge sub- plicit conversion functions. In the equivalent situation, for ject of debate in the C++ community back when cycles example, we could choose from among ceiling, floor, were precious and any stealth data “transformation” (no round, and truncate. matter how trivial) could incur a substantial performance There are similar situations where programmers think . (This was due to the copy-construction cascad- they know far more about a certain object’s type than the ing effect, which is no longer an issue in most modern could possibly know. Such a situation might arise object-oriented languages as they typically copy refer- with heterogeneous, predefined type collections, where ences instead of values.) Today, however, casting is often a programmers are unable to define a specific common ab- liability that actually causes runtime typing errors—even in straction after the fact (another would be to define wrap- programming languages with well-founded type systems pers with a common interface for the predefined types): like Java. Worse, it’s well known (especially among seasoned C/C++ programmers such as ourselves) that not all casts List links = should be allowed. For example, there is a natural promo- new ArrayList(); tion of short -> int -> long -> long long (in C) that links.add(“http://www.computer.org/cise”); is lossless; however, the reverse transformation is unnatu- links.add(new URL(“http://cise.aip.org/”)); ral, highly error-prone, and nonportable, especially in a //... heterogeneous computing world that still features 16-, 32-, for (final Object o : links) and 64-bit processors. Using conversion functions (instead if (o instanceof String) { of casts) lets you ensure that all meaningful conversions are String s = (String) o; performed correctly (forward and backward, by making all URL link = new URL(s); down conversions explicit and precise) with only a slight // do something with the link 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 is type errors (with some restrictions, as if (3 > 4) { much more complex and evaluates to we discuss in the sidebar “On Type- List l = 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

Sep t em b er /Oc t o b e r 2009 69 S cientific P rogramming

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 , 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- probable, binary patching is routinely type(y), or type(z). The C# language der takes a numeric argument x and used to change compiled code in a de- (from Microsoft’s .NET family) also returns a new function on another nu- ployed system, such as for updating op- supports automatic variable typing. meric 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 = such as switches, var x = new Integer(4); \y -> x + y that require near-zero downtime.) var x = new Integer(5); With static typing, we’d have known var z = x + y; Within the interpreter, we use the about the error inside the if statement keyword let to define new variables long before deploying the system. In the following typical example (the keyword isn’t necessary for top- Static typing also has a significant of higher-order programming, we level variable definitions in source performance benefit: because the use the to represent a files). Let’s now applymakeAdder to a compiler guarantees type safety, we custom comparison strategy as a func- suitable argument: don’t need the runtime checks found tion (in Java, encapsulated within an in dynamically typed languages and object) that we pass to the actual sort Prelude> makeAdder 3 our code runs faster (especially when function: No instance for (Show it’s all written in the same language). (t -> t)) But statically typed languages’ safe- List l = ... ty comes at a price: we must declare Comparator c = Given that applying makeAdder to a the type of each variable in the pro- new Comparator() { single argument results in a new func- gram, including formal arguments of public int compare( tion that expects another argument, methods and instance variables. This Integer l, Integer r) { it’s understandable that the interpret- can get tedious quickly as code gets ... } er complains that it doesn’t know how more complex, especially with higher- }; to print this (or any other) function. order programming. There are, how- Collections.sort(l, c); Instead, let’s use the interpreter’s :t ever, several emerging languages that (a shorthand for :type) command to automatically assign t ypes to variables. In the next section, we discuss how to take a look at the expression’s precise For example, in the Boo language (a do away with most of this tedium. 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) our cake and eat it, too? That is, y = new Integer(5) couldn’t we have the safety of static This type means that the function z = x + y typing without its tedium? Surpris- takes an argument of type t and re- ingly, the answer is yes! There are turns a result of type t, assuming that Here, x and y are both assigned the some functional languages that have t is a numeric type. Indeed, we can ap- static type of Integer (on first use) type systems as or more powerful than ply this function to another argument and z is assigned the same static type those of, say, Java, but that are capable and get the expected numeric result: (by inferring the expression’s result of figuring out the correct, intended type). If y were a Float instead of types of variables and functions in al- Prelude> (makeAdder 3) 4 Integer, we’d infer z to be a Float. most all situations. 7

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

Sep t em b er /Oc t o b e r 2009 71 S cientific P rogramming

Possible fix: add an Here is the whole story, step by step: and practice, typed functional pro- instance declaration for gramming languages compile well, (Num [t]) Prelude> countdown 5 and the same compilation techniques ==> (reverse . (flip take [0 work well with imperative languages These error messages say that it ..]) . (+ 1)) 5 like Java. Clean, OCaml, and F# of- found some numeric value instead of ==> reverse (flip take [0 ..] fer other, modern examples. Another either a character value or a list value. (1 + 5)) advantage could become even more If we narrow value 4’s type down from ==> reverse (flip take [0 ..] prominent in the multicore and novel a general number to a fixed-precision 6) computing era: if multiple expressions integer of type Int, then the message ==> reverse (take 6 [0 ..]) are ready to be evaluated, you can becomes clearer: ==> reverse [0,1,2,3,4,5] throw any number of cores at them. ==> [5,4,3,2,1,0] With , it’s Prelude> 3 : (4 :: Int) possible to delay the evaluation of a Couldn’t match expected Of course, any sane Haskell program- complex expression’s subexpressions type ‘[t]’ against mer would simply write until it’s required for computing the inferred type ‘Int’ final top-level result. This evaluation In the second argument of Prelude> let countdown n = strategy is called lazy evaluation—as ‘(:)’, namely ‘(4 :: reverse [0 .. n] opposed to the more familiar eager Int)’ 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 short-circuit evaluation, but without article, put together from predefined for actions, such as input/output, that the pitfalls of missing skipped subex- Haskell methods without recursion or by 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 = any expression in a program with its track of that are ready to reverse . (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 print of programs in lazy languages This terse definition deserves a bit and their correctness, similar to the should be higher than equivalent pro- of an explanation: way 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 of ad- Although side effects are common ertheless, the Glasgow Haskell Com- dition to 1, so it adds one to the in many modern scientific and high- piler now produces such effectively other 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- • [0 ..] is an (infinite!) list of non- cially for parallel-language . grams, and even up to three times faster negative integers; Because compilers have a notoriously in some cases. Recent work on Haskell • take takes only a given number of difficult time with side effects, we can’t runtime support on multicore hardware elements of a list, so it makes the in- use many optimization techniques— has shown promising initial results.2 finite list finite; and such as common-subexpression elimi- As we’ve already seen, lazy evaluation • reverse does the expected. nation or invariant hoisting. In theory gives us the seemingly ability

72 Co m p u t i n g in Sc i e n c e & En g i n e e r i n g to express infinite structures such as of IntOrStrings. Functions on data- t2 = Node “Hello” [ [0 ..] naturally and concisely. By con- types usually employ Node “World” [] trast, in conventional languages with to perform the case distinction among ] , we might represent the possible variants and to bind sub- infinite structures by wrapping the de- structures to variables: However, we can’t yet print values layed within a function or of these types: method. For example, in Java, we can add [] = (0,””) express infinite lists using theIterator add (AnInt i : xs) = Prelude> t1 abstraction: let (k, t) = add xs in (i + No instance for (Show ( k, t) Integer)) class Naturals implements add (AString s : xs) = Iterator { let (k, t) = add xs in (k, To solve this problem, we use Haskell’s private int value = 0; s ++ t) systematic overloading mechanism to public boolean hasNext() { define the missing show function used return true; } Prelude> add [AnInt 3, by the interpreter’s main loop to print public Integer next() { AString “adsf”, values: return value++; } AnInt 7, AString “qwer”] instance (Show a) => Show } (10,”adsfqwer”) (Tree a) where show Empty = “Empty” We can take this idea further and This list is homogeneous in the show (Node x ts) = develop a full-fledged library for pro- sense that all of its elements are of “Node “ ++ (show x) ++ gramming with infinite streams, as type IntOrString, but heteroge- “ “ ++ (show ts) others have already done for various neous in the sense that IntOrString languages. The lucid functional data- is a 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 a 3 already know how to print . Haskell streams and infinitary programming. very simple yet general tree type: already knows how to print its pre- defined basic types, such as Integer, data Tree a = Empty Algebraic Datatypes so we can print our tree exactly the | Node a [Tree a] Returning to our types discussion, al- way 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- either empty or is a node containing Node 1 [Node 2 [Node 4 type is a (possibly recursive) sum type of a value of some arbitrary type a and []],Node 3 [Node 5 []]] product types; sum and product types a list of children, which are also trees are formalizations of union and record/ and whose values, if any, are also of We can now define some t ypical tree tuple 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 doc- Node 2 [ umenting intent and usage: we’ll get data IntOrString = AnInt Int Node 4 [] an error if our implementation doesn’t | AString String ], match our stated intent: Node 3 [ We then define a function that Node 5 [] size Empty = 0 adds all the integers and concat- ] size (Node _ ts) = foldl (+) enates all the strings it finds in a list ] 1 (map size ts)

Sep t em b er /Oc t o b e r 2009 73 S cientific P rogramming

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- enation with the order of arguments ing the work queue, and the second flipped, so that the children get added traverse :: Tree a -> [Tree a] argument is a function for adding to the queue’s beginning, and we have traverse Empty = [] another list of elements to the queue; our last-in-first-out discipline back, re- traverse (t @ (Node x ts)) = this function determines the order in sulting in a depth-first . t : concat (map traverse ts) which we traverse the tree’s subtrees: While we pass a queue representa- tion and an associated operation openly In these functions, map applies a traverseUsingList [] _ = [] to the traverseUsingList function, function to each element in a list (in traverseUsingList (Empty : we could instead define a proper ab- this case, it recursively applies size to rest) addAll = stract datatype for queues in two ways: the children, ts), while concat flat- traverseUsingList rest through a tuple of one or more functions tens a list of lists to a simple list. Tree addAll that share and operate on a hidden data traversal converts a (nonlinear) tree to traverseUsingList representation, or through a nonstan- a linear sequence of references to all ((t @ (Node x ts)) : rest) dard extension that provides existential of the tree’s subtrees. As a result, we addAll = quantification of type variables (in con- no longer need a dedicated size func- t : traverseUsingList trast to universal quantification). tion because a tree’s size is simply the (addAll rest ts) addAll length of its linearization: We now have a functional version n this second installment on func- Prelude> rootValue t1 of the usual tree traversal . I tional programming, we’ve expand- 1 Initially, the only subtree in the work ed on the HOT languages notion and Prelude> size t1 queue is the tree itself. We then re- presented a case that having at least 5 peatedly take the first subtree from a basic knowledge of such languages Prelude> traverse t1 the work queue, add it to the result- can be part of a healthy programming [Node 1 [...],Node 2 ing linear structure, and add the cur- diet. Even if you’re not intent on us- [...],Node 4 [...], rent subtree’s children to the work ing functional programming anytime Node 3 [...],Node 5 [...]] queue. Given that our trees are finite, soon, the approach can help you get Prelude> map rootValue this continues until the work better results in any language, be- (traverse t1) queue is empty. We can now invoke cause many functional programming [1,2,4,3,5] this function using two different strat- ideas are used to implement optimiz- Prelude> (length . traverse) egies to add items to the work queue: ing compilers. Also, many languages t1 in one form or another (such as C#) 5 Prelude> map rootValue are introducing the ideas, and Micro- (traverseUsingList [t1] soft recently introduced a completely A limitation of our traverse (++)) functional , function is that the traversal order is [1,2,3,4,5] F#, into its languages suite. Given that hard-coded: the function performs Prelude> map rootValue Microsoft’s in the business of selling a depth-first tree traversal, descend- (traverseUsingList [t1] languages and tools, this is a big deal. ing as far down the leftmost path as (flip (++))) We’re equally convinced that clearly possible before visiting the rest of the [1,2,4,3,5] understanding typing systems can be tree. This is typical for recursive im- helpful when writing programs and plementations of tree traversal, where In the first case, addAll is standard avoiding the pitfalls entailed when the the implicit function- serves list concatenation, the current sub- decision is entirely left up to runtime. as a last-in-first-out work queue that tree’s children are appended to the end Our intention, however, is not to dis- stores the children yet to be visited. of the queue—amounting to a first-in- miss languages lacking well-founded We can make this function first-out discipline—and the result is type systems outright. We all use a vari- more flexible by parameterizing it a breadth-first traversal of the tree. In ety of languages in our work (Java, C#,

74 Co m p u t i n g in Sc i e n c e & En g i n e e r i n g Ha s k e l l 101 n addition to www.haskell.org, the official Haskell community wiki, we found Ithe 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 Multicore Haskell,” Proc. 14th ACM link to his slides) at http://blog.plover.com/talk/atypical-typing.html. Sigplan Int’l Conf. Functional Program- • The Learn You a Haskell for Great Good site offers a gentle Haskell tutorial at ming, ACM Press, 2009 (forthcoming); http://learnyouahaskell.com/chapters. www.haskell.org/~simonmar/papers/ • In November 2008, O’Reilly published the first edition of Real World Haskell multicore-ghc.pdf. by Bryan O’Sullivan, Don Stewart, and John Goerzen. They’ve since created a 3. W. Wadge and E. Ashcroft, Lucid, the Website with freely available content at http://book.realworldhaskell.org. 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 Haskel l it self has long been a n excel lent mers feel right at home and is particular- languages, software architecture and frame- choice for general software development, ly effective for creating domain-specific works, distributed systems, mobile and though its use in scientific and high- languages. If you’d like to learn more, embedded computing, human-computer performance computing has been the links in the “Haskell 101” sidebar interaction, and educational technology. hindered by a lack of library support will 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 cellent comments on various iterations George K. Thiruvathukal is an associate has created an ecosystem ranging from of this article and to Sergio Fanchiotti professor of computer science at Loyola a distributed version-control system for his helpful suggestions on useful University Chicago and is now an associate (DARCS) to the HAppS Web frame- Haskell resources. editor in chief of this magazine. His tech- work to the Haskore computer music nical interests include parallel/distributed system. The Glasgow Haskell Com- References systems, programming language design/ piler is very mature and produces highly 1. K. Hinsen, “The Promises of Functional implementation, and computer science optimized, fast-running code (it also Programming,” Computing in Science & across the disciplines. Thiruvathukal has a supports separate compilation through Eng., vol. 11, no. 4, 2009, pp. 86–90. PhD in computer science from the Illinois Haskell’s relatively simple module sys- 2. S. Marlow, S. Peyton Jones, and Institute of Technology. Contact him via tem). The Haskell folks have shown that S. Singh, “Runtime Support for http://gkt.etl.luc.edu. Call for Papers | General Interest

EEE Micro seeks general-interest submissions ization. Summaries of work in progress and de- for publication in upcoming issues. These scriptions of recently completed works are most Iworks should discuss the design, performance, welcome, as are tutorials. Micro does not accept or application of microcomputer and micropro- 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, fi gure, 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.

Sep t em b er /Oc t o b e r 2009 75