Hello, World!

The first step in learning any programming language is the 'hello, world' program. Here's the Haskell version.

main = putStrLn("Hello, world!")

In Haskell, as in C, you have to define "main" in order to create an executable. Haskell, however, does not use the curly braces.


Numbers

main = putStrLn(show(3+4*9))

To obtain numeric output, it is necessary for us to convert the result to a string in order to print it. We do that with show().


String Concatenation

main = putStrLn("3+4*9="++show(3+4*9))

String concatenation is accomplished with the ++ operator.


Let Blocks

main = let x = y+2 y = 3 z = y+1 in putStrLn("x="++show(x)++", z="++show(z))

In order to set variables you need to use a "let" block. You'll notice that both x and z depend on y, but y is defined after x and before z. This is possible because Haskell is a functional language. That means that variables are defined when they are set, and never change in value. That means that order of assignment is not important.

The other thing to notice is that blocks are defined by whitespace, just as they are in python. If you prefer to use curly braces, like C or java, this is possible.


Defining functions

Here we see our first example of a function that takes an argument. In this case, it is the inefficient implementation of the Fibonacci function.

One important thing to note here is that function names are never capitalized. Capitalized identifiers must refer to type names in Haskell.

fib 0 = 1 fib 1 = 1 fib n = fib (n-1) + fib (n-2) main = putStrLn(show(fib 10))

Here we see a slightly prettier version of the Fibonacci using what are called "patterns" to handle the condition where n < 2.

fib n | n==0 = 1 | n==1 = 1 | otherwise = fib (n-1) + fib (n-2) main = putStrLn(show(fib 10))

Another variant, called "guards" can be used to do the same thing.

One of the characteristics of the function defined above is that it is referentially transparent. This means that if a function is called twice with the same arguments, the compiler is free to replace the second function call with the value obtained by the first.

Furthermore, there is no way to determine what order fib(n-1) and fib(n-2) will evaluate. The compiler is free to attempt either computation first.


Lazy Evaluation

fib 0 = 1 fib 1 = 1 fib n = fib (n-1) + fib (n-2) main = let f1000 = fib 1000 hi = putStrLn("hello") in putStrLn(show(fib 10))

Haskell is lazy. That means, it doesn't compute a value if it does not have to. In this case, neither the variables f1000 nor hi are computed. Fib3 evaluates as quickly as fib2, and does not print the word "hello."


More than one line of output

main = do putStr("Line 1: ") putStrLn("one line of output") putStr("Line 2: "); putStrLn("another line of output") putStr("Line 3: "); putStrLn("another line of output")

In order to do more than one line of output, you need to use a "do" block. It is a special construct for stitching together a number of output commands. Inside a do block, each command will execute independently and in order. This gets around all the limitations imposed by functional programming.

Note also the use of putStr() vs. putStrLn(). The putStr() function does not output a carriage return / line feed.


Loops

again nlo nhi = if nlo == nhi then putStrLn("n = "++show(nlo)) else do putStrLn("n = "++show(nlo)) again (nlo+1) nhi main = again 1 10

Here we put all the information above together to teach you how to write a simple loop. Because the if statement was outside the do block we were forced to write the putStrLn("n="...) line twice.

again nlo nhi = let putn = putStrLn("n = "++show(nlo)) in if nlo == nhi then putn else do putn again (nlo+1) nhi main = again 1 10

That's still not elegant. However, there is another option. Case statements are allowed inside do blocks:

putStr "" otherwise -> again (nlo+1) nhi main = again 1 10 ]]>

The tricky thing about case statements is that their patterns must be compile time constants. You can't use "nhi ->" in your code. That's why we chose to switch on (nhi-nlo) rather than nlo.

Of course, we could have simply inverted the if and do blocks like so:

again nlo nhi = do putStrLn("n = "++show(nlo)) if nlo == nhi then putStr "" else again (nlo+1) nhi main = again 1 10

Recursion

If you are a C programmer, using recursion may worry you. The following C program would probably seg fault because it would completely exhaust the stack:

void inf(int n) { if(n == 0) { printf("done\n"); return; } inf(n-1); } int main() { inf(10000000); return 0; } ]]>

The equivalent Haskell program, however, is smart enough not to grow the stack because it knows that it is not really necessary since the above code is logically equivalent to a loop.

inf 0 = putStrLn("done") inf n = inf (n - 1) main = inf 10000000

Changing State

If you still want think imperatively, you can just use a function call whenever you normally use a state change.

void foo(int a) { printf("a=%d\n",a); a ++; printf("a=%d\n",a); } int main() { foo(1); return 0; } ]]> foo2 a = putStrLn("a="++show(a)) foo a = do putStrLn ("a="++show(a)) foo2 (a+1) main = foo 1

These loop and state examples probably make you think that Haskell is a cumbersome difficult language -- but really, this is not illustrative of the Haskell way of doing things. It is more like the C way of doing things shoe-horned into Haskell.

But hey, we have to start somewhere.

error in /home/sbrandt/javaregex.com/cios/xml/haskell/index.xml: out_dir does not exist in /home/.padre/sbrandt/javaregex.com/cios/work/haskell