Notes about the Haskell programming language.
To poke fun at the absurd verbosity of the python quicksort implementation:
quicksort [] = []
quicksort in@(x:xs) = [l | l <- in, l <= x] ++ [l | l <- in, l > x]
Advantages:
it’s statically typed, but still completely generic over all ordinal types
It is it’s own proof of correctness
It does the minimum required work
Disadvantages:
By using Haskell you are supporting the dark one
Anything more complex than quicksort (such as ‘hello world’) requires a PhD
-
lies,
main = print “hello, world!”
-
lies,
Monads.
Links
- Steven’s URL Dispatcher system. Light weight, generic URL dispatching system.
brehaut‘s thoughts on haskell
The Gentle !ntroduction to Haskell is very good. All but the monads section are easy to grasp and cover a huge amount of detail clearly.
Things that obscure haskell from a traditional point of programmers point of view.
Lazyness.
Pervasive lazyness takes some getting used to. The canonical haskell fibonacci is a good example of this;
fib = 1 : 1 : zipWith (+) fib (tail fib)without expecting lazyness this is very hard to grok, but trivial with it.The interactive repl ‘ghci’ is running inside
IO, and thus it can appear as if things are being evaluated strictly to casual inspection.Functions are everywhere - Even more than other functional languages, haskell is very function oriented
Eventually, everything is a function, or a restriction on a function.
There are many ways that new functions can come into existance in haskell, some of them are non-obvious to programmers of strict-imperative langauges. Some sources of new functions:
Function definitions (obviously)
Lambdas (also obvious)
Function composition (using
(.))— (.) is just a function (.) f g x = f (g x), although Haskellites would define it as f . g = x -> f (g x) (these are trivially equivalent) because seriously, who wouldn’t use an explicit lambda when given the opportunity? — Oliver
Partial application of a curried function
doNotationUnevaluated expressions aka thunks.
Monads
-
Monads are conceptually quite simple, but are confounded by a number of factors.
- As an abstraction they are able to do a number of different things, including controlling sequencing of operations, managing side effects, etc. As a result it appears to be difficult to provide meaningful concrete examples of monads that cover the abstraction fully.
- The notation of the type class is pretty intensive.
- Monads have no arguments of their own, but they can operate over closured values.
- For some reason, many people writing monad tutorials and introductions feel the need to using heavily abbreviated variable and function names through out their examples. Even the otherwise wonderful gentle introduction falls into this trap.
- 4 lines of State Monad code is very dense and cryptic, especially if you dont know what its doing.
- Much type-fu goes on
-
Monads are conceptually quite simple, but are confounded by a number of factors.
Three different ways to define new types (
type,newtype,data), a type system for the type system (kinds), ADTs through module exportsMany things that are primitives in other languages are library features in Haskell, such as imperitive operations, mutable variables!
Useful insights (Many gleened from Steven)
-
(.)is for function combination($)is for function application. eg:-
repeatN n io = sequence_ $ replicate n io -
repeatN n = sequence_ . replicate n - noting that the second definition doesnt need the explicit io arg.
-
- Using partial application to closure over values provides a startlingly elegant solution to an idiom that can potentially become long winded, or messy in many other languages.
- Use closures to get data into a monadic expression.
- Write functions with the expectation that they will be partially applied.
- Monads take notions of composability to an extreme. A monad generates a new HoF, with added semantics depending on its type. An amazing example of this is Software Transactional Memory.
- List comprehensions are a special monad notation
