For the past decades, it seems like the typical image associated with LISP and its dialects was that of hermit battle monks enlightened in the paths of Zen and lambda calculus, having at most a witty You Suck koan or two to spare for imperative-programming intruders daring to interrupt their musing over the beautiful nested structures of code before those are taken out with a swift brace throw before they even realize what has happened unto them, let alone get to draw their bulky proprietary arms.
I've been wishing to learn a "proper" functional language (SML, while neat in some aspects, essentially remains an academic toy) for a while now. LISP, as of late, appears to have been suffering from the huge piles of dust settling on it - most compilers/interpreters are rotten, broken and/or depending on bulky runtimes which make it hard to take it serious as a proper application development tool. Clean, from the Catholic University of Nijmegen, would have seemed a natural choice due to some past entanglements that shall go unmentioned, but, in fact, there was that other functional language it was derived from which has been gaining much more of a foothold lately. Haskell borrows SML's friendly typing system, while being packed with some pretty damn sweet constructions that exploit the awe-inspiring, though kind of opaque to channel, power of its lazy evaluation system (deliberately avoided in SML), possessing a well-isolated imperative subsystem (through monads) for "real-world" tasks, having a reasonably good machine code compiler and performing well enough to be given a chance even if it's probably never going to be quite up there with GNU's C/C++ compilers.
Here's some code I wrote up for the sake of testing, calculating multinomial expansions (i.e. expansions of terms like (x_1+...+x_n)^k, a still pretty well-known and useful generalization of the stock binomials):
import System
import Data.List
facs = scanl (*) 1 [1..]
fac n = head (drop (fromInteger n) facs)
-- multinomial a b = (x_1+...+x_a)^b in (F,[p_1,...,p_a]) pairs for Fx_1^{p_1}...x_a^{p_a}
multinomial :: Integer->Integer->[(Integer,[Integer])]
multinomial a b = let premultinomial :: Integer->Integer->[[Integer]]
premultinomial 1 b = [[b]]
premultinomial a 0 = [[0|q<-[1..a]]]
premultinomial a b = [ q:p | q<-[0..b], p<-premultinomial (a-1) (b-q) ]
in map (\r -> (fac b `div` (foldl (*) 1 (map fac r)),r)) (premultinomial a b)
main = do args <- getArgs
putStrLn( show (multinomial (read $ head args) (read $ head $ tail args) ))
(If called with 3 5 as command line parameters, its output is
[(1,[0,0,5]),(5,[0,1,4]),(10,[0,2,3]),(10,[0,3,2]),(5,[0,4,1]),
(1,[0,5,0]),(5,[1,0,4]),(20,[1,1,3]),(30,[1,2,2]),(20,[1,3,1]),
(5,[1,4,0]),(10,[2,0,3]),(30,[2,1,2]),(30,[2,2,1]),(10,[2,3,0]),
(10,[3,0,2]),(20,[3,1,1]),(10,[3,2,0]),(5,[4,0,1]),(5,[4,1,0]),
(1,[5,0,0])] .)
To spin on the previous metaphor, Haskell might be what happens if you take those venerable monks and provide them with leather longcoats and machine guns; for the reality-warping powers to complete the Matrix metaphor, I wouldn't make anything short of beating well-written C in performance count. |