Showing posts with label haskell. Show all posts
Showing posts with label haskell. Show all posts

2011-03-09

How to choose a Haskell array library

Choosing an array type in Haskell is a difficult task. For one-dimensional random access data structure the vector library seems to be the optimal choice most of the time. Things are more complicated if you happen to need two- or multi-dimensional arrays (matrices), access their blocks and slices as first-class structures (like in Python), enjoy destructive updates, use some linear algebra, interoperate with C and run your code in parallel...

I've reviewed what array libraries are available on Hackage, and compiled this feature matrix.

It is not complete and not finished, please let me know if I am mistaken about some of the libraries.

Data.Array and its variants from the array library seem to be the standard choice of multi-dimensional arrays for a Haskeller. They are not good anymore when you need to write array-to-array operations, access their blocks and slices, or need some linear algebra in general. Choosing the right variant is another question.

Data.Vector from the vector library is fast and has very nice API. It is going to become part of the Haskell Platform. Unfortunately, it is not usable for multi-dimensional arrays, and it doesn't support slices (strides). Only boxed variant is parallelizable.

Data.Packed.Vector and Data.Packed.Matrix from the hmatrix library provide a very nice API, and can do almost anything, if all you need is at most two-dimensional array (a matrix). A big warning sign: hmatrix is GPL. Not a sensible LGPL, but the poisonous GPL library. Also, Data.Packed.Vector and Data.Packed.Matrix are not parallelizable as far as I can see.

Data.Vector.*, Data.Matrix.* and Data.Tensor.* from the blas library. They can do all the standard linear algebra which the BLAS level 3 can offer. Their API is designed with BLAS API in mind. I didn't check if they are interoperable with C arrays, or if the elements are unboxed, or if the operations are parallelizable. The last release was in January 2009, it is not buildable on new GHC 7 yet.

Finally, there is new Data.Array.Repa arrays from the repa library. Nice thing about them: they are designed for parallelization. Not so nice thing about them: they don't give performance advantages on GHC 6, and are not yet buildable on GHC 7. Some more important limitations of the repa: no access to strides or array blocks, no built-in linear algebra, no interoperability with C.

I didn't include in the table Vec and vect libraries, which provide special case solutions in the low-dimension arrays and low-rank matrices. They are mostly tailored towards computer graphics.

2010-09-14

JavaScript highlighter for Haskell code

In this and in my other Blogspot blog I use SHJS to highlight syntax in Haskell snippets. SHJS is a JavaScript highlighter which uses language definitions from GNU Source-highlight.

To use it, you need to put online:

You may wish to download more than one language definition and concatenate all JavaScript files together. It's OK

Then put this somewhere in the <head>:

<head>
...
<script type="text/javascript" src="http://example.com/path/to/sh_main.min.js"></script>
<script type="text/javascript" src="http://example.com/path/to/sh_haskell.min.js"></script>
<link type="text/css" rel="stylesheet" href="http://example.com/path/to/stylesheet.css">
...
</head>

And add a callback to documents' body element:

<body onload="sh_highlightDocument();">

Finally, wrap your Haskell snippets with <pre class="sh_haskell"></pre>. This is how it looks:

-- Fibonacci numbers
fibs :: [Int]
fibs = 0 : 1 : zipWith (+) fibs (tail fibs)

As far as I know, Haskell language definition has already found its way to GNU Source-highlight, but the corresponding file is not yet shipped with SHJS. So you can download it either from my source repository, or generate from the language definition file (haskell.lang) yourself.

Haskell is a quirky language to highlight, but this language definition handles it reasonably well, better than the current google-code-prettify, and much better than the current GeSHi highlighter.

Update, 2011-01-25: Suprisingly, this highlighter is still better than more recent highlight.js and an alternative language definition for SHJS by Nicolas Wu (zenzike).

So this is the complete list of JavaScript highlighters for Haskell which I know about:

2010-09-04

LibZip 0.1: read and write zip archives from Haskell

I am happy to present a major release of my Haskell bindings to libzip library, to manipulate zip archives. It took me longer than I initially expected, but finally I like the result. Essential links first:

Hackage page Source repository Documentation Test coverage report An example

What's new

LibZip 0.1 is a complete remake. Under the hood it was made with bindings-DSL instead of C2Hs as before. The new LibZip offers a lot:

  • Support of almost all features of libzip: creating, reading, updating, renaming, and deleting files in zip archives, reading and writing file and archive comments. (LibZip 0.0 was read-only)
  • Support of various data sources: supply contents of a file from a list, from a file on disk, from a file in another archive, or even from a Haskell function.
  • A new monadic interface. It takes care of managing handlers and pointers behind the scenes. Less to type, less space for a user error.
  • Unit tests, better documentation and examples.

LibZip the only non-GPL library for Haskell to deal with zip archives. It is also fast to deal with large on-disk archives (more about it below).

Users of LibZip 0.0 (all 1.5 of them) may still use the old API by importing Codec.Archive.LibZip.LegacyZeroZero instead of Codec.Archive.LibZip. However, the old API is deprecated and will not be supported in the future.

LibZip vs zip-archive

There is another Haskell library to deal with zip archives, namely zip-archive. And here are the differences:

LibZip 0.1/libzipZip-Archive 0.1
LicenseBSDGPL v.2
Pure?NoYes
Large on-disk archivesFastSlow

Few notes about the last line. This is the actual reason why LibZip exists. Zip-archive was unacceptably memory-hungry and slow when dealing with large archives. So I started working on LibZip. I suppose that the problem with zip-archive is that it works with lazy bytestrings, not files. Bytestrings are sequential and don't have fseek. There is no reliable way to implement random access.

To get an idea what's the problem, get some moderately sized zip-archive off the web (for example, this one, 22 MiB), and print the list of files using both libraries.

With zip-archive, I used this code:

import Codec.Archive.Zip
import Control.Monad (liftM)
import System.Environment (getArgs)
import qualified Data.ByteString.Lazy as BS

main = mapM_ list =<< getArgs

list file = do
  a <- toArchive `liftM` BS.readFile file
  mapM_ print $ filesInArchive a

On my laptop, it takes 3.5 seconds to run against the downloaded archive:

$ time ./zip-archive-ls pak128-1.4.6--102.2.zip > /dev/null

real 0m3.499s
user 0m3.430s
sys 0m0.050s

And this is the code using LibZip:

import Codec.Archive.LibZip
import System.Environment (getArgs)

main = mapM_ list =<< getArgs

list file =
    withArchive [] file $ do
      names <- fileNames []
      lift $ mapM_ print names

It takes 0.05  seconds on the same file:

$ time ./libzip-ls pak128-1.4.6--102.2.zip > /dev/null

real 0m0.051s
user 0m0.040s
sys 0m0.010s

The difference gets more dramatic as the size of the archive increases. So, in my opinion, license issues aside, LibZip is a better choice when dealing with large archives on disk. Zip-archive may be more suitable choice to generate small archives in memory, without even hitting the disk.

Some implementation notes

I switched from C2Hs to bindings-DSL to implement the FFI bindings. And actually I liked bindings-DSL more. It is simple and makes fewer assumptions about the semantics of the C code. As a result, I had working low-level bindings very early. The rest was just to wrap them with a higher-level API to my liking. C2Hs experience was less smooth: in particular, when a C function is not designed as C2Hs expects it, I had to write wrappers manually anyway (for example, if a function returns a value and writes something to memory). Bindings-DSL seems to be better supported right now.

I changed the order of file names and file access flags in all API functions. File name being the last seems to be more useful for partial function application. An example of such order of arguments is:

fileSize :: [FileFlag] -> FilePath -> Archive Int

I ditched ByteString support from the new API. ByteStrings are my Haskell nightmare: there are too many flavours of them to support, and they are not interchangeable. With LibZip 0.0 I had to support two versions of otherwise identical code, all to discover some time later that I need to pack . unpack bytestrings in the application code (impendance mismatch with another library, which chose to use a different flavour of bytestrings).

In this version I chose to use lists as input and output buffers to some functions (sourceBuffer, sourcePure, readBytes, readContents). I suspect this may have negative performance impact, but it needs to be studied. Marshalling of the byte buffers is another question. I suppose that sourceFile and sourcePure may help to workaround this problem if it actually arises. User feedback is required.

Some of the library functions (most notably sourceBuffer) accept Strings as data buffers. This is convenient for testing, but those Strings should not contains code points above 255. The library doesn't handle text encodings. The user is responsible of providing a correctly encoded byte stream to the library.

Libzip can use C callbacks as data source. LibZip bindings can wrap a pure Haskell function and make the C library call it when necessary (see sourcePure). It is not as convenient as the usual lazy evaluation in Haskell, but, hopefully, may somewhat compensate for impurity of the library. I consider adding also sourceIO.

Thanks?

LibZip is under BSD3 licencse. So it is Free. If you want to say “thanks”, consider using this Flattr button:

Flattr this

I think Flattr is a great idea and I'll be glad if more people start using it.

If you use the library, please let me know. It will make me happier, and will motivate me more to support and improve the library.

2010-07-07

The hierarchy of numeric typeclasses in Haskell

Some time ago I posted this in my Russian blog. Re-posting it here, for it's inconvenient to not be able to find it when googling in English. I use it for reference :-)

Haskell Numeric typeclasses

Non-abstract types are gathered together in gray frames. Polymorphic types and type classes have rounded boxes. Their possible type parameters are indicated with inversed rhombus arrows.

2009-06-15

Haskell horrors

As a beginner Haskell programmer I still remember its horrors. Time to write them down. It is my first functional language, so I have to learn new concepts and new language in parallel, but it is fun. I hope these notes may be useful to other beginners. I'll give also some examples in Python, to show that Haskell in fact is not so scary for beginners.

1. Lambdas

We call it lembas or waybread, and it is more strengthening than any food by men, by all accounts…

This is why I learned about Haskell. I was just curious what those lambdas are. A paper Conception, evolution, and application of functional programming languages by Paul Hudak was really helpful to get started (It's kind of old, and, probably, there are better introductions, but I read this one first).

Lambda expression is an essence of ‘function’: it's an expression of form

\lambda x \;.\; \text{expression with $x$}

The value of this expression is a function, which takes one argument (x) and calculates something with it (an expression on the right hand side of the dot). There is much mathematical theory about lambdas, but sometimes I just think about \lambda as a keyword to define functions. In fact, I was already used to lambdas in Python, where they look like:

lambda x: expression with x

They were very useful in filter() and reduce(). They may be used almost anywhere where a function name is required, but lambdas don't have names. Hence, they are called Anonymous functions.

Sometimes in Python I give them names to define new functions on-the-fly

add_42 = lambda x: x + 42

Name add_42 now refers to a function. This is almost the same as defining functions in a more usual way:

def add_42(x):
    return x+42

Now, what about Haskell? It's pretty much the same. \ symbol stays for \lambda, -> stays for dot:

\x -> expression with x

We can even give them names to define reusable functions:

add_42 = \x -> x + 42

Very similar, isn't it?

There is a subtle point. As soon as I started reading about Haskell, I saw lambda-expressions which looked a little bit strange at first:

\x -> \y -> an expression with x and y

What are those multiple ‘arrows’ I asked? The answer was really simple and very helpful to understand Haskell code.

All Haskell functions are functions of one argument. This may sound like a restriction initially, but then it turns out to be a very convenient concept. A function of n arguments may be represented as a function of one argument producing another function of n–1 arguments. This is called currying.

Once we know this, we can read any expression with many arrows:

\x -> (\y -> an expression with x and y)

The value of the expression is a function which takes an argument and produces another function which takes yet another argument. This expression as a whole behaves as if it were a function of two arguments. For example, we may apply such a function to two arguments in ghci (Haskell interpreter):

ghci> (\x -> \y -> x + y ) 3 4
7
Of course, there is a shorthand form where we can write it as a function of two arguments (please note also that we don't need parentheses for function arguments):
ghci> (\x y -> x + y) 3 4
7

But it is very useful to know that internally every function of two or more arguments is actually a function of only one argument. This also helps reading function types later. For example, a type of map function reads like

map :: (a -> b) -> [a] -> [b]

I usually read it like this: ‘function map takes two arguments, a function from a to b and a list of a and produces a list of b’. But sometimes it is more natural to read as written:

map :: (a -> b) -> ([a] -> [b])

‘A function which takes a function from a to b and produces a function which converts a list of a to a list of b’.

These simple ideas about lambda functions were enough to get me started with Haskell and to understand most of the examples and tutorials.

2. Equals sign

‘If there's no meaning in it,’ said the King, ‘that saves a world of trouble, you know, as we needn't try to find any. And yet I don't know,’

As for me, equals sign = was probably the most important Haskell symbol to understand the language. I think its semantics is underemphasized in tutorials. For example, it's the only ‘keyword’ which is missing on a Haskell keywords' wikipage.

Unlike in most imperative languages where = means an assignemt (i.e. an action), in Haskell it means that its left hand side equals its right hand side.

‘Equals’ is not ‘becomes’. It means that something is equal to something else. Always. Just like in mathematics. a = b in Haskell means that a equals b by definition, a is equivalent to b.

So, = in Haskell serves to write definitions. It defines all sorts of things, but it defines them statically. It doesn't depend on the order of execution. It is something we may rely upon.

This may sound too evident, but this is a major difference for anyone with an imperative background. Now we may give names to our anonymous functions:

add = \x -> \y -> x + y
To tell the truth, it's not very readable, so most of the time functions are defined like this:
add x y = x + y
But this one is still a definition of add.

3. Type classes

Significant benefits arise from sharing a common type system, a common toolset, and so forth. These technical advantages translate into important practical benefits such as enabling groups with moderately differing needs to share a language rather than having to apply a number of specialized languages. — Bjarne Stroustrup
Type system in Haskell is beatiful. It feels very natural to reason about. And probably type classes is the least alien concept for people coming to Haskell from procedural/OO world. At least they are for me. But type classes are not the same thing as classes in C++ or Java. They are much more like abstract template classes in C++, because they
  • define only an abstract interface (don't provide a default implementation)
  • allow independent implementations (that is any class may become an instance of the type class if it implements class methods)
  • are polymorphic by their nature and support inheritance
  • don't have state variables
Once it's accepted that type classes are not C++ classes, but abstract interfaces, and class instances are not “objects”, but implementations of the abstract interfaces, Haskell becomes friendly and easy. I suggest to read an excellent a wiki article OOP vs type classes which covers this topic in much more detail.

4. Monads

And as every present state of a simple substance is naturally a consequence of its preceding state, so its present is pregnant with its future.

Now matter how gentle your introduction to Haskell is, sooner or later you stumble into the wall of Monads. Yes, there is some serious abstract mathematics behind them.

But I learned that it is not necessary to understand abstract mathematics to use monads, and they are indeed a very nice programming technique. They looked a little bit strange to me initially, but understanding monads is easier than memorizing countless OO design-patterns and using them right.

There are plenty of tutorials on monads, so I wont repeat them and expect that you've already read one or two. So, what's wrong with monads? For my imperatively prepared mind spoiled with years of object oriented thinking, monads looked strange. They may look like an abstract container class with a mystic >>= method:

class Monad m where
  return :: a -> m a
  (>>=) :: m a -> (a -> m b) -> m b
  fail :: String -> m a
Well, if return is a constructor, then why such a strange name? If this is a container class, how can I take values out? And what's the point of applying a function inside monad (>>= method, also known as bind) if we cannot take the result out of it?

Let's answer the last question first. What is the purpose of bind (>>=)? Monads are and are not containers. They are wrappers around computations rather than values (return). But they wrap computations not to store them conveniently in monadic boxes, but to link them together. Think standard bricks rather than boxes, or Adapter pattern. Each monad defines a standard interface to pass the result from one computation to the other (>>=). No matter what happens, the result is still in the same monad (even fail).

The most simple programming analogy I found is pipes in unix shell. Monads provide a unidirectional pipeline for computations. The same unix pipes do. For example:

$ seq 1 5 | awk '{print $1 " " $1*$1*$1 ;}'
1 1
2 8
3 27
4 64
5 125

seq produced a list of integers. awk calculated cubes for all of them. What's cool about this? We have two loosely coupled programs which work together. Text stream flows from left to write, each subsequent program in a pipe is capable to read this stream, do something with it, and output another text stream. Text stream is a common computation result, | binds computations together.

Monads are similar. >>= takes the inner computation from the monad on the left and puts it into the computation on the right, which always produces the same monad. You probably already know that lists and Maybe type in Haskell are monads. For example, if we have a simple computation which returns a pair of a number and its cube into the monad:

\x -> return (x, x^3)

then we can ‘pipe’ the list into this computation:

ghci> [1,2,3,4,5] >>= \x -> return (x,x^3)
[(1,1),(2,8),(3,27),(4,64),(5,125)]

Please note that we received a list of pairs. It's the same monad (the list). But if we ‘pipe’ a Maybe value into the same computation, we get the same monad as input (Maybe):

ghci> Just 5 >>= \x -> return (x,x^3)
Just (5,125)

You see, we can construct a pipeline of two computations, and the behaviour of this pipeline depends on the context (i.e. on the Monad instance), not on the computations themselves. Unlike unix pipes, Monads are type-safe, type system takes care that the output of one monadic computation is compatible with the input of the other. And unlike unix pipes, we can define our own binding rules (>>=). Like ‘don't join more than 42 computations in a row’ or ‘look at the input, and do one thing or the other’. Monads encapsulate rules how to bind computations together.

Now, I hope, you understand monads at least as well as I do (not necessarily perfectly). I'd like to discuss some mnemonics. Why return is named ‘return’?

In most languages, return returns result from a function. In Haskell, it acts as constructor for monads. Weird. Well, let's look at how >>= works, we see that it extracts a value from the monad on the left, and then binds it to the argument of the function on the right. This function should return the result back into monad, so that the next >>= can work. This is the first mnemonics.

The second mnemonics. On the top level any Haskell program is executed in IO monad (main's type is IO ()), which can do input/output (and sequential operations in general). Thus, monadic code is executed on the top level and it calls any pure code when necessary, not otherwise. So any pure value if not discarded is eventually returned into the monad of the caller.

With these two explanations the name return does not sound so weird for me as before. I don't pretend these explanations are technically correct.

The next question, how to take a value of the computation out of the monad? Well, it's not always possible by design. For example, you cannot take a pure value outside of the IO monad. If we have such a one-way monad, the only thing we can do, is pipeline the value to the next computation. Fortunately, Haskell has a nice do-notation, which makes such pipelining look almost identical to imperative programming languages. These two programs describe the same thing, with do-notation:

main :: IO ()
main = do
  name <- getLine
  putStrLn ("Hi, " ++ name)
and with explicit >>=:
main :: IO ()
main = getLine >>= \name -> putStrLn ("Hi, " ++ name)
An equivalent Python program:
from sys import stdin, stdout
if __name__ == "__main__":
    name = stdin.readline()
    stdout.write("Hi, " + name)
However, sometimes it is possible to take the pure value out of the monadic computation. This is not possible with the standard monad interface, so the developer of the monad should provide means to extract values. For example, it is possible to extract values from Maybe monad using fromMaybe function:
ghci> fromMaybe 0 $ Just 3
3
ghci> fromMaybe 0 $ Nothing
0

Résumé on monads

So, bind (>>=) allows to put various monadic computations together and combine them. Anywhere, where we have a chain of computation, monads fit naturally. Particular monad implementation may encapsulate custom rules of combining two computations together. Name return may be confusing for beginners, but we have to remember that it returns a value into the monad, not from the monad. Understanding this helped me a lot.

5. Scary words

I know nothing except the fact of my ignorance.
Finally, I have to acknowledge, after months of studying Haskell and being able to write useful programs in it, there is still a lot of concepts in the Haskell world which I don't know anything about or have only a vague idea. I call these kind of concepts “scary words”. But still I see people creating and using new libraries which implement those concepts. Let's face it: Haskell remains a test bed for research. It's both good and bad. It's good, because it feels like a bleeding edge is really close, and you may benefits from the new approaches if you like. And it's bad, because if you want to use some cool new library, you may find that it heavily relies on a concept you are not very comfortable with. For example, there is a modern XML library, HXT. It uses arrows heavily. Arrows provide more general combinators than monads, but it took me much more than a day to understand them. Strictly speaking, Arrows are not part of the language, but they are an actively used concept in practice. There are many other examples like this. I think that it's important not to be afraid of the “scary words”. Fortunately, all the concepts are well documented. There are papers which explain the ideas. Personally I decided to learn such concepts as need arise. At least it promises to be manageable and entertaining.

Conclusion

I mentioned 5 simple ideas which helped me to get used to Haskell: lambdas are just a way to write functions, a function of two or more arguments is actually a function of only one argument which returns another function, type classes correspond to abstract polymorphic interfaces in the object oriented wold, monads are just a tool to merge computations together, and scary words are just scary words. I hope this helps someone else. This post is also available in Russian.