Learn Haskell in 10 minutes
From HaskellWiki
| Line 3: | Line 3: | ||
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. It's closest popular relative is probably the ML family of languages. | 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. It's closest popular relative is probably the ML family of languages. | ||
| - | The most common Haskell compiler is GHC. You can download GHC from [http://www.haskell.org/ghc/download_ghc_661.html http://www.haskell.org/ghc/download_ghc_661.html]. GHC binaries are available for 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. | + | The most common Haskell compiler is GHC. You can download GHC from [http://www.haskell.org/ghc/download_ghc_661.html http://www.haskell.org/ghc/download_ghc_661.html]. GHC binaries are available for Linux, FreeBSD, MacOS, Windows, and Solaris. Once you've installed GHC, you get two programs you're interested in right now: <tt>ghc</tt>, and <tt>ghci</tt>. 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. |
== Simple Expressions == | == Simple Expressions == | ||
| - | You can type most math expressions directly into ghci and get an answer. | + | You can type most math expressions directly into <tt>ghci</tt> and get an answer. |
Prelude> <hask>3 * 5</hask> | Prelude> <hask>3 * 5</hask> | ||
| Line 68: | Line 68: | ||
(The 4 was input. The 16 was a result.) | (The 4 was input. The 16 was a result.) | ||
| - | There is actually another way to write <hask>do</hask> 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. | + | There is actually another way to write <hask>do</hask> blocks. If you leave off the braces and semicolons, then indentation becomes significant. This doesn't work so well in <tt>ghci</tt>, but try putting the file in a source file (say, <tt>Test.hs</tt>) and build it. |
<haskell> | <haskell> | ||
| Line 78: | Line 78: | ||
</haskell> | </haskell> | ||
| - | You can build with ghc --make Test.hs, and the result will be called Test. (On Windows, Test.exe) You get an <hask>if</hask> statement as a bonus. | + | You can build with <tt>ghc --make Test.hs</tt>, and the result will be called <tt>Test</tt>. (On Windows, <tt>Test.exe</tt>) You get an <hask>if</hask> statement as a bonus. |
Every line that starts in the same column as the first <hask>putStrLn</hask> is part of the <hask>do</hask> block. This is called "layout", and Haskell uses it to avoid making you put in statement terminators and braces all the time. (The <hask>then</hask> and <hask>else</hask> phrases have to be indented for this reason: if they started in the same column, they'd be separate statements, which is wrong.) | Every line that starts in the same column as the first <hask>putStrLn</hask> is part of the <hask>do</hask> block. This is called "layout", and Haskell uses it to avoid making you put in statement terminators and braces all the time. (The <hask>then</hask> and <hask>else</hask> 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.) | ||
== Simple Types == | == Simple Types == | ||
| Line 111: | Line 113: | ||
<hask>gcd 15 20 :: (Integral t) => t</hask> | <hask>gcd 15 20 :: (Integral t) => t</hask> | ||
| - | These type | + | These types use "type classes." They mean: |
* <hask>42</hask> can be used as any numeric type. (This is why I was able to declare <hask>5<hask> as either an Int or a Double earlier.) | * <hask>42</hask> can be used as any numeric type. (This is why I was able to declare <hask>5<hask> as either an Int or a Double earlier.) | ||
* <hask>42.0</hask> can be any fractional type, but not an integral type. | * <hask>42.0</hask> can be any fractional type, but not an integral type. | ||
* <hask>gcd 15 20</hask> (which is a function call, incidentally) can be any integral type, but not a fractional type. | * <hask>gcd 15 20</hask> (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): | There are five numeric types in the Haskell "prelude" (the part of the library you get without having to import anything): | ||
| Line 127: | Line 127: | ||
* <hask>Rational<hask> is a fraction type, with no rounding error. | * <hask>Rational<hask> is a fraction type, with no rounding error. | ||
| - | All five of these | + | All five of these are '''instances''' of the <hask>Num</hask> type class. The first two are '''instances''' of <hask>Integral</hask>, and the last two are '''instanced''' of <hask>Fractional</hask>. |
Putting it all together, | Putting it all together, | ||
| Line 138: | Line 138: | ||
No instance for (Integral Double) | No instance for (Integral Double) | ||
| - | 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> | ||
| + | <hask>()</hask> | ||
| + | Prelude> :t <hask>()</hask> | ||
| + | <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 a function or I/O action if you don't want to return anything. | ||
== Structured Data == | == Structured Data == | ||
| Line 185: | Line 192: | ||
Prelude> <hask>[1 .. 5]</hask> | Prelude> <hask>[1 .. 5]</hask> | ||
<hask>[1,2,3,4,5]</hask> | <hask>[1,2,3,4,5]</hask> | ||
| - | Prelude> <hask>map (+2) [1 .. 5]</hask> | + | Prelude> <hask>map (+ 2) [1 .. 5]</hask> |
<hask>[3,4,5,6,7]</hask> | <hask>[3,4,5,6,7]</hask> | ||
Prelude> <hask>filter (> 2) [1 .. 5]</hask> | Prelude> <hask>filter (> 2) [1 .. 5]</hask> | ||
| Line 202: | Line 209: | ||
== Function Definitions == | == Function Definitions == | ||
| - | === | + | |
| - | === | + | We wrote a function earlier, called <hask>main</hask>: |
| - | = | + | |
| - | = | + | <haskell> |
| + | main = do putStrLn "What is 2 + 2?" | ||
| + | x <- readLn | ||
| + | if x == 4 | ||
| + | then putStrLn "You're right!" | ||
| + | else putStrLn "You're wrong!" | ||
| + | </haskell> | ||
| + | |||
| + | Let's write another, and call it <hask>factorial</hask>. I'm also adding a module header, which is good form. | ||
| + | |||
| + | <haskell> | ||
| + | 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!" | ||
| + | </haskell> | ||
| + | |||
| + | Build again with <tt>ghc --make Test.hs</tt>. And, | ||
| + | |||
| + | $ ./Test | ||
| + | What is 5! ? | ||
| + | 120 | ||
| + | You're right! | ||
| + | |||
| + | There's a function. Just like the built-in functions, it can be called as <hask>factorial 5</hask> without needing parentheses. | ||
| + | |||
| + | Now ask <tt>ghci</tt> for the type. | ||
| + | |||
| + | $ ghci Test.hs | ||
| + | << GHCi banner >> | ||
| + | Ok, modules loaded: Main. | ||
| + | Prelude Main> :t <hask>factorial</hask> | ||
| + | <hask>factorial :: (Num a) => a -> a</hask> | ||
| + | |||
| + | Function types are written with the argument type, a <hask> -> </hask>, and the result type. (This also has the type class <hask>Num</hask>.) | ||
| + | |||
| + | Factorial can be simplified by writing it with case analysis. | ||
| + | |||
| + | <haskell> | ||
| + | factorial 0 = 1 | ||
| + | factorial n = n * factorial (n - 1) | ||
| + | </haskell> | ||
| + | |||
== Syntax == | == Syntax == | ||
=== Let === | === Let === | ||
Revision as of 14:36, 13 July 2007
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. It's closest popular relative is probably the ML family of languages.
The most common Haskell compiler is GHC. You can download GHC from http://www.haskell.org/ghc/download_ghc_661.html. GHC binaries are available for 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>15Prelude>
15Prelude>
16Strings are in "double quotes." You can concatenate them with
"Hello"Prelude>
"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>6Prelude>
6Prelude>
7Prelude>
1.4142135623730951Prelude>
TruePrelude>
7
3 The Console
I/O actions can be used to read from and write to the console. Some common ones include:
Prelude>Hello, HaskellPrelude>
9Prelude>
TrueThe
2 + 2 = 4Prelude>
ABCDE 12345Reading can be done with
4 16
(The 4 was input. The 16 was a result.)
There is actually another way to writemain = do putStrLn "What is 2 + 2?" x <- readLn if x == 4 then putStrLn "You're right!" else putStrLn "You're 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.)
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 use5Prelude>
5.0
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> :tThings get more interesting for numbers.
Prelude> :tThese types use "type classes." They mean:
- can be used as any numeric type. (This is why I was able to declare42can be any fractional type, but not an integral type.5<hask> as either an Int or a Double earlier.)
* <hask>42.0 - (which is a function call, incidentally) can be any integral type, but not a fractional type.gcd 15 20
There are five numeric types in the Haskell "prelude" (the part of the library you get without having to import anything):
- is an integer with at least 30 bits of precision.Int
- is an integer with unlimited precision.Integer
- is a single precision floating point number.Float
- is a double precision floating point number.Double
- type class. The first two are instances ofRational<hask> is a fraction type, with no rounding error.
All five of these are '''instances''' of the <hask>Num, and the last two are instanced ofIntegral.Fractional
Putting it all together,
Prelude>7Prelude>
<interactive>:1:0:
No instance for (Integral Double)
The final type worth mentioning here is 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]Prelude>
[1,2,3,4,5]Prelude>
[1,3,5,7,9]Prelude>
[True,False,True]
Strings are just lists of characters.
Prelude>"Hello"The
"CHello"
Tuples hold a fixed number of values, which can have different types.
Prelude>(1,True)Prelude>
[(1,'a'),(2,'b'),(3,'c'),(4,'d'),(5,'e')]The last example used
The types are probably what you'd expect.
Prelude> :tLists are used a lot in Haskell. There are several functions that do nice things with them.
Prelude>TODO: Can't think of a good way to describe fold
There are two nice functions on ordered pairs (tuples of two elements):
Prelude>6 Function Definitions
We wrote a function earlier, calledmain = do putStrLn "What is 2 + 2?" x <- readLn if x == 4 then putStrLn "You're right!" else putStrLn "You're wrong!"
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
Now ask ghci for the type.
$ ghci Test.hs << GHCi banner >> Ok, modules loaded: Main.Prelude Main> :t
Factorial can be simplified by writing it with case analysis.
factorial 0 = 1 factorial n = n * factorial (n - 1)
