Thursday, September 6, 2007

Lesson 1: Hello, World!

Installing Haskell and supporting tools


In this series I am using the following software packages on a Debian based GNU/Linux distribution:

In some of the initial lessons I assume you are as well, but if you are not, you should still be able to follow along. Once we really get into the language, it should not matter much, until we get to advanced lessons that use features only found in recent versions of GHC.

First run:

$ sudo apt-get install emacs21 ghc6

Then check that haskell-mode 2.3 or higher is available:

$ sudo apt-cache policy haskell-mode
Installed: 2.3-0cnr1
Candidate: 2.3-0cnr1
Version table:
*** 2.3-0cnr1 0
500 skipjack-feisty/main Packages
100 /var/lib/dpkg/status

If it is, run the following command and skip to the next section:

$ sudo apt-get install haskell-mode

If the version of haskell-mode is less than 2.3, then temporarily add this line to your /etc/apt/sources.list:

deb skipjack-feisty main

and run:

$ sudo apt-get update
$ sudo apt-get install haskell-mode

and, finally, remove the skipjack-feisty line from your sources.list.
Configure Emacs and Haskell mode

Add the following lines to your ~/.emacs file and restart emacs:

;; Font Locking, Programming Modes, and Compilation settings

(global-font-lock-mode 1)
;; maximum colors
(setq font-lock-maximum-decoration t)

;; extra key bindings
(global-set-key "\M-C" 'compile)
(global-set-key "\C-^" 'next-error)
(global-set-key "\C-\M-g" 'goto-line)

;; use spaces instead of tabs
(setq-default indent-tabs-mode nil)

;; haskell mode configuration
(setq auto-mode-alist
(append auto-mode-alist
'(("\\.[hg]s$" . haskell-mode)
("\\.hic?$" . haskell-mode)
("\\.hsc$" . haskell-mode)
("\\.chs$" . haskell-mode)
("\\.l[hg]s$" . literate-haskell-mode))))
(autoload 'haskell-mode "haskell-mode"
"Major mode for editing Haskell scripts." t)
(autoload 'literate-haskell-mode "haskell-mode"
"Major mode for editing literate Haskell scripts." t)

;adding the following lines according to which modules you want to use:
(require 'inf-haskell)

(add-hook 'haskell-mode-hook 'turn-on-font-lock)
;(add-hook 'haskell-mode-hook 'turn-off-haskell-decl-scan)
;(add-hook 'haskell-mode-hook 'turn-off-haskell-doc-mode)
(add-hook 'haskell-mode-hook 'turn-on-haskell-indent)
;(add-hook 'haskell-mode-hook 'turn-on-haskell-simple-indent)
;(add-hook 'haskell-mode-hook 'turn-on-haskell-hugs)
(add-hook 'haskell-mode-hook 'turn-on-haskell-ghci)
(add-hook 'haskell-mode-hook
(lambda ()
(setq haskell-program-name "ghci")
(setq haskell-ghci-program-name "ghci6"))))

Hello, World

Run emacs HelloWorld.hs, and enter the following program:

module Main where

main = putStrLn "Hello, World!"

To save press Control-x followed by Control-s. In emacs-speak this is written as C-x C-s.
Loading the code into GHC Interactive

Now we can load the code into the GHC intepreter by pressing C-c C-l.
This should open another buffer in emacs that looks something like this:

___ ___ _
/ _ \ /\ /\/ __(_)
/ /_\// /_/ / / | | GHC Interactive, version 6.6.1, for Haskell 98.
/ /_\\/ __ / /___| |
\____/\/ /_/\____/|_| Type :? for help.

Loading package base ... linking ... done.
Prelude> :load "/tmp/HelloWorld.hs"
[1 of 1] Compiling Main ( /tmp/HelloWorld.hs, interpreted )
Ok, modules loaded: Main.

To switch between the code and ghci buffers press C-x o, or use the mouse and click inside the buffer you want active.

To run the main function, just type main and hit enter at the *Main> prompt:

*Main> main
Hello, World!

Compiling the Code

Switch back to the HelloWorld.hs buffer and enter M-C. The M stands for Meta, which is usually the key labelled Alt, and the C is uppercase. So you will need to press Alt-Shift-c. At the bottom of the emacs window it should now say:

Compile command: make -k

Change it to

Compile command: ghc --make -O2 HelloWorld.hs -o helloWorld

You should now have a *compilation* buffer that looks like

cd /tmp/
ghc --make -O2 HelloWorld.hs -o helloWorld
[1 of 1] Compiling Main ( HelloWorld.hs, HelloWorld.o )
Linking helloWorld ...

Compilation finished at Thu Sep 6 12:33:33

Now open a shell, and run the executable:

lain:/tmp $ ./helloWorld
Hello, World!
lain:/tmp $

The parts of the command-line are pretty straight forward:

The name of the compiler

This tells the compiler that we want to compile a module and all of its dependencies, and produce an executable that we can run.

This tells the compiler that we want to enable level 2 optimizations (the highest level available). This should result in an executable that runs faster.

This is the name of the file that contains the main function.

-o helloWorld
This tells the compiler that the executable should be named helloWorld. If you do not specify a name, it will probably default to a.out

Parts of the Program

The program is pretty short, but let's go over the details anyway.

module Main where

This tells the compiler that this file contains the Main module.
When your program is run, it always starts at the main function in the module Main.

main = putStrLn "Hello, World"

This defines a function named main that prints Hello, World followed by a carriage return to stdout. putStrLn is a function, and "Hello, World" is a String. To call a function with an argument, we simply put some whitespace after the function name followed by the argument.

Cool Stuff We Learned

This lesson was a bit long, because we had to install stuff, but we learned some cool stuff:

  1. Haskell code can be compiled to an executable, or run interactively

  2. Haskell syntax is very clean. We do not need lots of characters like {}(); to get stuff done

  3. We are not required to declare the types of our functions anywhere


Anonymous said...

Looking forward to Lesson 2.

Unknown said...

Thanks for taking the time to do this. I have been using the Haskell for C Programmers tutorial but I could never get very far into it without getting bored or asking myself "Why is this so mind-bendingly difficult?"

Anonymous said...

Hi. Thanks for this.

But using XEmacs on windows XP, this doesn't work as expected. XEmacs ends up sending the HS filename with single back slashes to ghcii and ghcii can't load the file.

Anyone knows a workaround for this?

Jeremy Shaw said...

I am not sure how to fix the problem with XEmacs, but as a temporary work around you can press C-c C-b to start the GHCi buffer. Then switch into the GHCi buffer and run:

Prelude> :l HelloWorld.hs

If you make some changes to HelloWorld.hs you can reload it by running

*Main> :r

If you already have Visual Studio .NET, you may be able to use Visual Haskell. I have not used it, but it looks nice.

Anonymous said...

Awesome. I just bought the book "An Intro to Lambda Calculus for Computer Scientists". Between the book and your tutorial perhaps I can evolve haskell as a useful tool.

Unknown said...

You don't need to put all these lines into your .emacs, because the haskell-mode package comes with its own initialisation file (/etc/emacs/site-start.d/50haskell-mode.el).
But you need to uncomment the line (add-hook 'haskell-mode-hook 'turn-on-haskell-ghci) to get the GHCi support.

Anonymous said...

Teach Haskell, NOT emacs

Anonymous said...

Well, to start with... thanks.
but the the link for the emacs mode is dead (at least for me it's inaccessible)

do you have a mirror for it?

Unknown said...

I love the idea of learnhaskell in 5 min. I just have a suggestion that you should post like some kind of practice exercise or something at the end of every lesson, and post the answer key in next lesson. That way user get in some practice too.

Anonymous said...

"Teach Haskell, NOT emacs"

I'm glad the author discussed emacs, efficiency should be learned from the start. It's harder to break bad habits than it is to learn new ones. I hope your lessons continue to incorporate emacs in the teaching of Haskell. I also hope future lessons are slow paced, don't jump too quick to monads. ;)

Anonymous said...

Hi Jeremy.

Thanks for posting these articles. Do you intend on expanding them into a series? Perhaps covering classes, internet functionality, etc?



Anonymous said...

Thanks a ton for doing this man
it was helpful

Raoul Duke said...

many thanks! it was close enough to get me going.

Justin said...

Instead of typing the command each time you can do this at the top of the file:

-- -*- compile-command:"ghc --make -O2 hello.hs -o hello.exe"; -*-

Then M-x compile will automatically contain that line, and you can copy and paste it into each new .hs file you make.

Anonymous said...

Hi all,

Nice post.
I have one question though, is it possible to automatically run script without typing "main" in ghci console buffer, after loading script?


karl said...


This post was really helpful! I was wrestling with haskell-mode for last 2 or 3 hrs. Now I can start learning Haskell on myself.

Anonymous said...

thanks so much for this. And screw the comment that said "teach Haskell, not Emacs." I'm completely new to all this stuff, and have spent HOURS over the past few days trying to do anything at all in Haskell. Every other source I found made too many assumptions that I was set up correctly, and nothing worked.

This is the first (and only, so far) place I've found where I found step by step instructions on what to do, and it worked. Fantastic. Finally. Much appreciated.