Personal tools

Learn Haskell in 10 minutes

From HaskellWiki

(Difference between revisions)
Jump to: navigation, search
m (The console)
(Topics that don't fit in 10 minute limit)
(One intermediate revision by one user not shown)
Line 9: Line 9:
 
You can type most math expressions directly into <tt>ghci</tt> and get an answer. <tt>Prelude></tt> is the default GHCi prompt.
 
You can type most math expressions directly into <tt>ghci</tt> and get an answer. <tt>Prelude></tt> is the default GHCi prompt.
   
Prelude> <hask>3 * 5</hask>
+
Prelude> 3 * 5
 
15
 
15
Prelude> <hask>4 ^ 2 - 1</hask>
+
Prelude> 4 ^ 2 - 1
 
15
 
15
Prelude> <hask>(1 - 5)^(3 * 2 - 4)</hask>
+
Prelude> (1 - 5)^(3 * 2 - 4)
 
16
 
16
   
 
Strings are in "double quotes." You can concatenate them with <hask>++</hask>.
 
Strings are in "double quotes." You can concatenate them with <hask>++</hask>.
   
Prelude> <hask>"Hello"</hask>
+
Prelude> "Hello"
 
"Hello"
 
"Hello"
Prelude> <hask>"Hello" ++ ", Haskell"</hask>
+
Prelude> "Hello" ++ ", Haskell"
 
"Hello, Haskell"
 
"Hello, Haskell"
   
 
Calling [[function]]s is done by putting the arguments directly after the function. There are no parentheses as part of the function call:
 
Calling [[function]]s is done by putting the arguments directly after the function. There are no parentheses as part of the function call:
   
Prelude> <hask>succ 5</hask>
+
Prelude> succ 5
 
6
 
6
Prelude> <hask>truncate 6.59</hask>
+
Prelude> truncate 6.59
 
6
 
6
Prelude> <hask>round 6.59</hask>
+
Prelude> round 6.59
 
7
 
7
Prelude> <hask>sqrt 2</hask>
+
Prelude> sqrt 2
 
1.4142135623730951
 
1.4142135623730951
Prelude> <hask>not (5 < 3)</hask>
+
Prelude> not (5 < 3)
 
True
 
True
Prelude> <hask>gcd 21 14</hask>
+
Prelude> gcd 21 14
 
7
 
7
   
Line 42: Line 42:
 
[[Introduction to IO |I/O actions]] can be used to read from and write to the console. Some common ones include:
 
[[Introduction to IO |I/O actions]] can be used to read from and write to the console. Some common ones include:
   
Prelude> <hask>putStrLn "Hello, Haskell"</hask>
+
Prelude> putStrLn "Hello, Haskell"
 
Hello, Haskell
 
Hello, Haskell
Prelude> <hask>putStr "No newline"</hask>
+
Prelude> putStr "No newline"
 
No newline
 
No newline
Prelude> <hask>print (5 + 4)</hask>
+
Prelude> print (5 + 4)
 
9
 
9
Prelude> <hask>print (1 < 2)</hask>
+
Prelude> print (1 < 2)
 
True
 
True
   
Line 55: Line 55:
 
If you need multiple I/O actions in one expression, you can use a <hask>do</hask> block. Actions are separated by semicolons.
 
If you need multiple I/O actions in one expression, you can use a <hask>do</hask> block. Actions are separated by semicolons.
   
Prelude> <hask>do { putStr "2 + 2 = " ; print (2 + 2) }</hask>
+
Prelude> do { putStr "2 + 2 = " ; print (2 + 2) }
 
2 + 2 = 4
 
2 + 2 = 4
Prelude> <hask>do { putStrLn "ABCDE" ; putStrLn "12345" }</hask>
+
Prelude> do { putStrLn "ABCDE" ; putStrLn "12345" }
 
ABCDE
 
ABCDE
 
12345
 
12345
Line 63: Line 63:
 
Reading can be done with <hask>getLine</hask> (which gives back a <hask>String</hask>) or <hask>readLn</hask> (which gives back whatever type of value you want). The <hask> <- </hask> symbol is used to assign a name to the result of an I/O action.
 
Reading can be done with <hask>getLine</hask> (which gives back a <hask>String</hask>) or <hask>readLn</hask> (which gives back whatever type of value you want). The <hask> <- </hask> symbol is used to assign a name to the result of an I/O action.
   
Prelude> <hask>do { n <- readLn ; print (n^2) }</hask>
+
Prelude> do { n <- readLn ; print (n^2) }
 
4
 
4
 
16
 
16
Line 89: Line 89:
 
So far, not a single [[type]] declaration has been mentioned. That's because Haskell does type inference. You generally don't have to declare types unless you want to. If you do want to declare types, you use <hask>::</hask> to do it.
 
So far, not a single [[type]] declaration has been mentioned. That's because Haskell does type inference. You generally don't have to declare types unless you want to. If you do want to declare types, you use <hask>::</hask> to do it.
   
Prelude> <hask>5 :: Int</hask>
+
Prelude> 5 :: Int
 
5
 
5
Prelude> <hask>5 :: Double</hask>
+
Prelude> 5 :: Double
 
5.0
 
5.0
   
Line 98: Line 98:
 
You can also ask <tt>ghci</tt> what type it has chosen for something. This is useful because you don't generally have to declare your types.
 
You can also ask <tt>ghci</tt> what type it has chosen for something. This is useful because you don't generally have to declare your types.
   
Prelude> :t <hask>True</hask>
+
Prelude> :t True
<hask>True :: Bool</hask>
+
True :: Bool
Prelude> :t <hask>'X'</hask>
+
Prelude> :t 'X'
<hask>'X' :: Char</hask>
+
'X' :: Char
Prelude> :t <hask>"Hello, Haskell"</hask>
+
Prelude> :t "Hello, Haskell"
<hask>"Hello, Haskell" :: [Char]</hask>
+
"Hello, Haskell" :: [Char]
   
 
(In case you noticed, <hask>[Char]</hask> is another way of saying <hask>String</hask>. See the [[#Structured data|section on lists]] later.)
 
(In case you noticed, <hask>[Char]</hask> is another way of saying <hask>String</hask>. See the [[#Structured data|section on lists]] later.)
Line 109: Line 109:
 
Things get more interesting for numbers.
 
Things get more interesting for numbers.
   
Prelude> :t <hask>42</hask>
+
Prelude> :t 42
<hask>42 :: (Num t) => t</hask>
+
42 :: (Num t) => t
Prelude> :t <hask>42.0</hask>
+
Prelude> :t 42.0
<hask>42.0 :: (Fractional t) => t</hask>
+
42.0 :: (Fractional t) => t
Prelude> :t <hask>gcd 15 20</hask>
+
Prelude> :t gcd 15 20
<hask>gcd 15 20 :: (Integral t) => t</hask>
+
gcd 15 20 :: (Integral t) => t
   
 
These types use "type classes." They mean:
 
These types use "type classes." They mean:
Line 134: Line 134:
 
Putting it all together,
 
Putting it all together,
   
Prelude> <hask>gcd 42 35 :: Int</hask>
+
Prelude> gcd 42 35 :: Int
 
7
 
7
Prelude> <hask>gcd 42 35 :: Double</hask>
+
Prelude> gcd 42 35 :: Double
 
 
 
<interactive>:1:0:
 
<interactive>:1:0:
Line 143: Line 143:
 
The final type worth mentioning here is <hask>()</hask>, pronounced "unit." It only has one value, also written as <hask>()</hask> and pronounced "unit."
 
The final type worth mentioning here is <hask>()</hask>, pronounced "unit." It only has one value, also written as <hask>()</hask> and pronounced "unit."
   
Prelude> <hask>()</hask>
+
Prelude> ()
<hask>()</hask>
+
()
Prelude> :t <hask>()</hask>
+
Prelude> :t ()
<hask>() :: ()</hask>
+
() :: ()
   
 
You can think of this as similar to the <tt>void</tt> keyword in C family languages. You can return <hask>()</hask> from an I/O action if you don't want to return anything.
 
You can think of this as similar to the <tt>void</tt> keyword in C family languages. You can return <hask>()</hask> from an I/O action if you don't want to return anything.
Line 156: Line 156:
 
Lists are used to hold multiple values of the same type.
 
Lists are used to hold multiple values of the same type.
   
Prelude> <hask>[1, 2, 3]</hask>
+
Prelude> [1, 2, 3]
 
[1,2,3]
 
[1,2,3]
Prelude> <hask>[1 .. 5]</hask>
+
Prelude> [1 .. 5]
 
[1,2,3,4,5]
 
[1,2,3,4,5]
Prelude> <hask>[1, 3 .. 10]</hask>
+
Prelude> [1, 3 .. 10]
 
[1,3,5,7,9]
 
[1,3,5,7,9]
Prelude> <hask>[True, False, True]</hask>
+
Prelude> [True, False, True]
 
[True,False,True]
 
[True,False,True]
   
 
Strings are just lists of characters.
 
Strings are just lists of characters.
   
Prelude> <hask>['H', 'e', 'l', 'l', 'o']</hask>
+
Prelude> ['H', 'e', 'l', 'l', 'o']
 
"Hello"
 
"Hello"
   
 
The <hask>:</hask> operator appends an item to the beginning of a list. (It is Haskell's version of the <tt>cons</tt> function in the Lisp family of languages.)
 
The <hask>:</hask> operator appends an item to the beginning of a list. (It is Haskell's version of the <tt>cons</tt> function in the Lisp family of languages.)
   
Prelude> <hask>'C' : ['H', 'e', 'l', 'l', 'o']</hask>
+
Prelude> 'C' : ['H', 'e', 'l', 'l', 'o']
 
"CHello"
 
"CHello"
   
 
Tuples hold a fixed number of values, which can have different types.
 
Tuples hold a fixed number of values, which can have different types.
   
Prelude> <hask>(1, True)</hask>
+
Prelude> (1, True)
 
(1,True)
 
(1,True)
Prelude> <hask>zip [1 .. 5] ['a' .. 'e']</hask>
+
Prelude> zip [1 .. 5] ['a' .. 'e']
 
[(1,'a'),(2,'b'),(3,'c'),(4,'d'),(5,'e')]
 
[(1,'a'),(2,'b'),(3,'c'),(4,'d'),(5,'e')]
   
Line 186: Line 186:
 
The types are probably what you'd expect.
 
The types are probably what you'd expect.
   
Prelude> :t <hask>['a' .. 'c']</hask>
+
Prelude> :t ['a' .. 'c']
<hask>['a' .. 'c'] :: [Char]</hask>
+
['a' .. 'c'] :: [Char]
Prelude> :t <hask>[('x', True), ('y', False)]</hask>
+
Prelude> :t [('x', True), ('y', False)]
<hask>[('x', True), ('y', False)] :: [(Char, Bool)]</hask>
+
[('x', True), ('y', False)] :: [(Char, Bool)]
   
 
Lists are used a lot in Haskell. There are several functions that do nice things with them.
 
Lists are used a lot in Haskell. There are several functions that do nice things with them.
   
Prelude> <hask>[1 .. 5]</hask>
+
Prelude> [1 .. 5]
<hask>[1,2,3,4,5]</hask>
+
[1,2,3,4,5]
Prelude> <hask>map (+ 2) [1 .. 5]</hask>
+
Prelude> map (+ 2) [1 .. 5]
<hask>[3,4,5,6,7]</hask>
+
[3,4,5,6,7]
Prelude> <hask>filter (> 2) [1 .. 5]</hask>
+
Prelude> filter (> 2) [1 .. 5]
<hask>[3,4,5]</hask>
+
[3,4,5]
   
 
There are two nice functions on ordered pairs (tuples of two elements):
 
There are two nice functions on ordered pairs (tuples of two elements):
   
Prelude> <hask>fst (1, 2)</hask>
+
Prelude> fst (1, 2)
<hask>1</hask>
+
1
Prelude> <hask>snd (1, 2)</hask>
+
Prelude> snd (1, 2)
<hask>2</hask>
+
2
Prelude> <hask>map fst [(1, 2), (3, 4), (5, 6)]</hask>
+
Prelude> map fst [(1, 2), (3, 4), (5, 6)]
<hask>[1,3,5]</hask>
+
[1,3,5]
   
 
Also see [[how to work on lists]]
 
Also see [[how to work on lists]]
Line 251: Line 251:
 
<< GHCi banner >>
 
<< GHCi banner >>
 
Ok, modules loaded: Main.
 
Ok, modules loaded: Main.
Prelude Main> :t <hask>factorial</hask>
+
Prelude Main> :t factorial
<hask>factorial :: (Num a) => a -> a</hask>
+
factorial :: (Num a) => a -> a
   
 
Function types are written with the argument type, then <hask> -> </hask>, then the result type. (This also has the type class <hask>Num</hask>.)
 
Function types are written with the argument type, then <hask> -> </hask>, then the result type. (This also has the type class <hask>Num</hask>.)
Line 348: Line 348:
   
 
[[Category:Tutorials]]
 
[[Category:Tutorials]]
Languages: [[Learn Haskell in 10 minutes|en]] [[Cn/十分钟学会 Haskell|zh/cn]] [[10分で学ぶHaskell|ja]]
+
Languages: [[Learn Haskell in 10 minutes|en]] [[Cn/十分钟学会 Haskell|zh/cn]] [[10分で学ぶHaskell|ja]] [[Haskell em 10 minutos|pt]]

Revision as of 16:52, 15 March 2012

Contents

1 Overview

Haskell is a functional (that is, everything is done with function calls), statically, implicitly typed (types are checked by the compiler, but you don't have to declare them), lazy (nothing is done until it needs to be) language. Its closest popular relative is probably the ML family of languages (which are not, however, lazy languages).

The most common Haskell compiler is GHC. You can download GHC from http://www.haskell.org/ghc/download.html . GHC binaries are available for GNU/Linux, FreeBSD, MacOS, Windows, and Solaris. Once you've installed GHC, you get two programs you're interested in right now: ghc, and ghci. The first compiles Haskell libraries or applications to binary code. The second is an interpreter that lets you write Haskell code and get feedback right away.

2 Simple expressions

You can type most math expressions directly into ghci and get an answer. Prelude> is the default GHCi prompt.

 Prelude> 3 * 5
 15
 Prelude> 4 ^ 2 - 1
 15
 Prelude> (1 - 5)^(3 * 2 - 4)
 16
Strings are in "double quotes." You can concatenate them with
++
.
 Prelude> "Hello"
 "Hello"
 Prelude> "Hello" ++ ", Haskell"
 "Hello, Haskell"

Calling functions is done by putting the arguments directly after the function. There are no parentheses as part of the function call:

 Prelude> succ 5
 6
 Prelude> truncate 6.59
 6
 Prelude> round 6.59
 7
 Prelude> sqrt 2
 1.4142135623730951
 Prelude> not (5 < 3)
 True
 Prelude> gcd 21 14
 7

3 The console

I/O actions can be used to read from and write to the console. Some common ones include:

 Prelude> putStrLn "Hello, Haskell"
 Hello, Haskell
 Prelude> putStr "No newline"
 No newline
 Prelude> print (5 + 4)
 9
 Prelude> print (1 < 2)
 True
The
putStr
and
putStrLn
functions output strings to the terminal. The
print
function outputs any type of value. (If you
print
a string, it will have quotes around it.) If you need multiple I/O actions in one expression, you can use a
do
block. Actions are separated by semicolons.
 Prelude> do { putStr "2 + 2 = " ; print (2 + 2) }
 2 + 2 = 4
 Prelude> do { putStrLn "ABCDE" ; putStrLn "12345" }
 ABCDE
 12345
Reading can be done with
getLine
(which gives back a
String
) or
readLn
(which gives back whatever type of value you want). The
 <-
symbol is used to assign a name to the result of an I/O action.
 Prelude> do { n <- readLn ; print (n^2) }
 4
 16

(The 4 was input. The 16 was a result.)

There is actually another way to write
do
blocks. If you leave off the braces and semicolons, then indentation becomes significant. This doesn't work so well in ghci, but try putting the file in a source file (say, Test.hs) and build it.
main = do putStrLn "What is 2 + 2?"
          x <- readLn
          if x == 4
              then putStrLn "You're right!"
              else putStrLn "You're wrong!"
You can build with ghc --make Test.hs, and the result will be called Test. (On Windows, Test.exe) You get an
if
expression as a bonus. The first non-space character after
do
is special. In this case, it's the p from
putStrLn
. Every line that starts in the same column as that
p
is another statement in the
do
block. If you indent more, it's part of the previous statement. If you indent less, it ends the
do
block. This is called "layout", and Haskell uses it to avoid making you put in statement terminators and braces all the time. (The
then
and
else
phrases have to be indented for this reason: if they started in the same column, they'd be separate statements, which is wrong.)

(Note: Do not indent with tabs if you're using layout. It technically still works if your tabs are 8 spaces, but it's a bad idea. Also, don't use proportional fonts -- which apparently some people do, even when programming!)

4 Simple types

So far, not a single type declaration has been mentioned. That's because Haskell does type inference. You generally don't have to declare types unless you want to. If you do want to declare types, you use
::
to do it.
 Prelude> 5 :: Int
 5
 Prelude> 5 :: Double
 5.0

Types (and type classes, discussed later) always start with upper-case letters in Haskell. Variables always start with lower-case letters. This is a rule of the language, not a naming convention.

You can also ask ghci what type it has chosen for something. This is useful because you don't generally have to declare your types.

 Prelude> :t True
 True :: Bool
 Prelude> :t 'X'
 'X' :: Char
 Prelude> :t "Hello, Haskell"
 "Hello, Haskell" :: [Char]
(In case you noticed,
[Char]
is another way of saying
String
. See the section on lists later.)

Things get more interesting for numbers.

 Prelude> :t 42
 42 :: (Num t) => t
 Prelude> :t 42.0
 42.0 :: (Fractional t) => t
 Prelude> :t gcd 15 20
 gcd 15 20 :: (Integral t) => t

These types use "type classes." They mean:

  • 42
    can be used as any numeric type. (This is why I was able to declare
    5
    as either an
    Int
    or a
    Double
    earlier.)
  • 42.0
    can be any fractional type, but not an integral type.
  • gcd 15 20
    (which is a function call, incidentally) can be any integral type, but not a fractional type.

There are five numeric types in the Haskell "prelude" (the part of the library you get without having to import anything):

  • Int
    is an integer with at least 30 bits of precision.
  • Integer
    is an integer with unlimited precision.
  • Float
    is a single precision floating point number.
  • Double
    is a double precision floating point number.
  • Rational
    is a fraction type, with no rounding error.
All five are instances of the
Num
type class. The first two are instances of
Integral
, and the last three are instances of
Fractional
.

Putting it all together,

 Prelude> gcd 42 35 :: Int
 7
 Prelude> gcd 42 35 :: Double
 
 <interactive>:1:0:
     No instance for (Integral Double)
The final type worth mentioning here is
()
, pronounced "unit." It only has one value, also written as
()
and pronounced "unit."
 Prelude> ()
 ()
 Prelude> :t ()
 () :: ()
You can think of this as similar to the void keyword in C family languages. You can return
()
from an I/O action if you don't want to return anything.

5 Structured data

Basic data types can be easily combined in two ways: lists, which go in [square brackets], and tuples, which go in (parentheses).

Lists are used to hold multiple values of the same type.

 Prelude> [1, 2, 3]
 [1,2,3]
 Prelude> [1 .. 5]
 [1,2,3,4,5]
 Prelude> [1, 3 .. 10]
 [1,3,5,7,9]
 Prelude> [True, False, True]
 [True,False,True]

Strings are just lists of characters.

 Prelude> ['H', 'e', 'l', 'l', 'o']
 "Hello"
The
:
operator appends an item to the beginning of a list. (It is Haskell's version of the cons function in the Lisp family of languages.)
 Prelude> 'C' : ['H', 'e', 'l', 'l', 'o']
 "CHello"

Tuples hold a fixed number of values, which can have different types.

 Prelude> (1, True)
 (1,True)
 Prelude> zip [1 .. 5] ['a' .. 'e']
 [(1,'a'),(2,'b'),(3,'c'),(4,'d'),(5,'e')]
The last example used
zip
, a library function that turns two lists into a list of tuples.

The types are probably what you'd expect.

 Prelude> :t ['a' .. 'c']
 ['a' .. 'c'] :: [Char]
 Prelude> :t [('x', True), ('y', False)]
 [('x', True), ('y', False)] :: [(Char, Bool)]

Lists are used a lot in Haskell. There are several functions that do nice things with them.

 Prelude> [1 .. 5]
 [1,2,3,4,5]
 Prelude> map (+ 2) [1 .. 5]
 [3,4,5,6,7]
 Prelude> filter (> 2) [1 .. 5]
 [3,4,5]

There are two nice functions on ordered pairs (tuples of two elements):

 Prelude> fst (1, 2)
 1
 Prelude> snd (1, 2)
 2
 Prelude> map fst [(1, 2), (3, 4), (5, 6)]
 [1,3,5]

Also see how to work on lists

6 Function definitions

We wrote a definition of an IO action earlier, called
main
:
main = do putStrLn "What is 2 + 2?"
          x <- readLn
          if x == 4
              then putStrLn "You're right!"
              else putStrLn "You're wrong!"
Now, let's supplement it by actually writing a function definition and call it
factorial
. I'm also adding a module header, which is good form.
module Main where
 
factorial n = if n == 0 then 1 else n * factorial (n - 1)
 
main = do putStrLn "What is 5! ?"
          x <- readLn
          if x == factorial 5
              then putStrLn "You're right!"
              else putStrLn "You're wrong!"

Build again with ghc --make Test.hs. And,

 $ ./Test
 What is 5! ?
 120
 You're right!
There's a function. Just like the built-in functions, it can be called as
factorial 5
without needing parentheses.

Now ask ghci for the type.

 $ ghci Test.hs
 << GHCi banner >>
 Ok, modules loaded: Main.
 Prelude Main> :t factorial
 factorial :: (Num a) => a -> a
Function types are written with the argument type, then
 ->
, then the result type. (This also has the type class
Num
.)

Factorial can be simplified by writing it with case analysis.

factorial 0 = 1
factorial n = n * factorial (n - 1)

7 Convenient syntax

A couple extra pieces of syntax are helpful.

secsToWeeks secs = let perMinute = 60
                       perHour   = 60 * perMinute
                       perDay    = 24 * perHour
                       perWeek   =  7 * perDay
                   in  secs / perWeek
The
let
expression defines temporary names. (This is using layout again. You could use {braces}, and separate the names with semicolons, if you prefer.)
classify age = case age of 0 -> "newborn"
                           1 -> "infant"
                           2 -> "toddler"
                           _ -> "senior citizen"
The
case
expression does a multi-way branch. The special label
_
means "anything else".

8 Using libraries

Everything used so far in this tutorial is part of the Prelude, which is the set of Haskell functions that are always there in any program.

The best road from here to becoming a very productive Haskell programmer (aside from practice!) is becoming familiar with other libraries that do the things you need. Documentation on the standard libraries is at http://haskell.org/ghc/docs/latest/html/libraries/. There are modules there with:

module Main where
 
import qualified Data.Map as M
 
errorsPerLine = M.fromList
    [ ("Chris", 472), ("Don", 100), ("Simon", -5) ]
 
main = do putStrLn "Who are you?"
          name <- getLine
          case M.lookup name errorsPerLine of
              Nothing -> putStrLn "I don't know you"
              Just n  -> do putStr "Errors per line: "
                            print n
The
import
says to use code from
Data.Map
and that it will be prefixed by
M
. (That's necessary because some of the functions have the same names as functions from the prelude. Most libraries don't need the
as
part.)

If you want something that's not in the standard library, try looking at http://hackage.haskell.org/packages/hackage.html or this wiki's applications and libraries page. This is a collection of many different libraries written by a lot of people for Haskell. Once you've got a library, extract it and switch into that directory and do this:

 runhaskell Setup configure
 runhaskell Setup build
 runhaskell Setup install

On a UNIX system, you may need to be root for that last part.

9 Topics that don't fit in 10 minute limit

Languages: en zh/cn ja pt