Learn Haskell in 10 minutes
From HaskellWiki
(→Topics that don't fit in 10 minute limit) |
|||
| (39 intermediate revisions not shown.) | |||
| Line 1: | Line 1: | ||
== Overview == | == Overview == | ||
| - | Haskell is a functional (that is, everything is done with function calls), statically, implicitly typed ( | + | Haskell is a functional (that is, everything is done with function calls), statically, implicitly typed ([[type]]s 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 | + | 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]], [[BSD | FreeBSD]], [[Mac OS X |MacOS]], [[Windows]], and [[Solaris]]. Once you've installed [[GHC]], you get two programs you're interested in right now: <tt>ghc</tt>, and <tt>[[GHC/GHCi | 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 | + | == Simple expressions == |
| - | You can type most math expressions directly into <tt>ghci</tt> and get an answer. | + | You can type most math expressions directly into <tt>ghci</tt> and get an answer. <tt>Prelude></tt> is the default GHCi prompt. |
| - | Prelude | + | Prelude> 3 * 5 |
15 | 15 | ||
| - | Prelude | + | Prelude> 4 ^ 2 - 1 |
15 | 15 | ||
| - | Prelude | + | 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 | + | Prelude> "Hello" |
"Hello" | "Hello" | ||
| - | Prelude | + | Prelude> "Hello" ++ ", Haskell" |
"Hello, Haskell" | "Hello, Haskell" | ||
| - | Calling | + | Calling [[function]]s is done by putting the arguments directly after the function. There are no parentheses as part of the function call: |
| - | Prelude | + | Prelude> succ 5 |
6 | 6 | ||
| - | Prelude | + | Prelude> truncate 6.59 |
6 | 6 | ||
| - | Prelude | + | Prelude> round 6.59 |
7 | 7 | ||
| - | Prelude | + | Prelude> sqrt 2 |
1.4142135623730951 | 1.4142135623730951 | ||
| - | Prelude | + | Prelude> not (5 < 3) |
True | True | ||
| - | Prelude | + | Prelude> gcd 21 14 |
7 | 7 | ||
| - | == The | + | == The console == |
| - | 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 | + | Prelude> putStrLn "Hello, Haskell" |
Hello, Haskell | Hello, Haskell | ||
| - | Prelude | + | Prelude> putStr "No newline" |
| - | No | + | No newline |
| + | Prelude> print (5 + 4) | ||
9 | 9 | ||
| - | Prelude | + | Prelude> print (1 < 2) |
True | True | ||
| - | The <hask>putStr</hask> and <hask>putStrLn</hask> functions output strings. The <hask>print</hask> function outputs any type of value. (If you <hask>print</hask> a string, it will have quotes around it.) | + | The <hask>putStr</hask> and <hask>putStrLn</hask> functions output strings to the terminal. The <hask>print</hask> function outputs any type of value. (If you <hask>print</hask> a string, it will have quotes around it.) |
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 | + | Prelude> do { putStr "2 + 2 = " ; print (2 + 2) } |
2 + 2 = 4 | 2 + 2 = 4 | ||
| - | Prelude | + | Prelude> do { putStrLn "ABCDE" ; putStrLn "12345" } |
ABCDE | ABCDE | ||
12345 | 12345 | ||
| - | 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 | + | 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 | + | Prelude> do { n <- readLn ; print (n^2) } |
4 | 4 | ||
16 | 16 | ||
| Line 78: | Line 79: | ||
</haskell> | </haskell> | ||
| - | 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> | + | 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> expression as a bonus. |
| - | Every line that starts in the same column as | + | The first non-space character after <hask>do</hask> is special. In this case, it's the <tt>p</tt> from <hask>putStrLn</hask>. Every line that starts in the same column as that <hask>p</hask> is another statement in the <hask>do</hask> block. If you indent more, it's part of the previous statement. If you indent less, it ends 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.) | + | (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!) |
| - | == Simple | + | == 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 <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 | + | Prelude> 5 :: Int |
5 | 5 | ||
| - | Prelude | + | Prelude> 5 :: Double |
5.0 | 5.0 | ||
| - | + | [[Type]]s (and type [[class]]es, 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 [[Studly capitals|naming convention]]. | |
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 | + | Prelude> :t True |
| - | + | True :: Bool | |
| - | Prelude> :t | + | Prelude> :t 'X' |
| - | + | 'X' :: Char | |
| - | Prelude> :t | + | Prelude> :t "Hello, Haskell" |
| - | + | "Hello, Haskell" :: [Char] | |
| - | (In case you noticed, <hask>[Char]</hask> is another way of saying <hask>String</hask>. See the 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.) |
Things get more interesting for numbers. | Things get more interesting for numbers. | ||
| - | Prelude> :t | + | Prelude> :t 42 |
| - | + | 42 :: (Num t) => t | |
| - | Prelude> :t | + | Prelude> :t 42.0 |
| - | + | 42.0 :: (Fractional t) => t | |
| - | Prelude> :t | + | Prelude> :t gcd 15 20 |
| - | + | gcd 15 20 :: (Integral t) => t | |
These types use "type classes." They mean: | These types use "type classes." They mean: | ||
| Line 129: | Line 130: | ||
* <hask>Rational</hask> is a fraction type, with no rounding error. | * <hask>Rational</hask> is a fraction type, with no rounding error. | ||
| - | All five are '''instances''' of the <hask>Num</hask> type class. The first two are '''instances''' of <hask>Integral</hask>, and the last | + | All five are '''instances''' of the <hask>Num</hask> type class. The first two are '''instances''' of <hask>Integral</hask>, and the last three are '''instances''' of <hask>Fractional</hask>. |
Putting it all together, | Putting it all together, | ||
| - | Prelude | + | Prelude> gcd 42 35 :: Int |
7 | 7 | ||
| - | Prelude | + | Prelude> gcd 42 35 :: Double |
<interactive>:1:0: | <interactive>:1:0: | ||
| Line 142: | 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 | + | Prelude> () |
| - | + | () | |
| - | Prelude> :t | + | Prelude> :t () |
| - | + | () :: () | |
| - | You can think of this as similar to the <tt>void</tt> keyword in C family languages. You can return <hask>()</hask> from | + | 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. |
| - | == Structured | + | == Structured data == |
Basic data types can be easily combined in two ways: lists, which go in [square brackets], and tuples, which go in (parentheses). | Basic data types can be easily combined in two ways: lists, which go in [square brackets], and tuples, which go in (parentheses). | ||
| Line 155: | 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 | + | Prelude> [1, 2, 3] |
[1,2,3] | [1,2,3] | ||
| - | Prelude | + | Prelude> [1 .. 5] |
[1,2,3,4,5] | [1,2,3,4,5] | ||
| - | Prelude | + | Prelude> [1, 3 .. 10] |
[1,3,5,7,9] | [1,3,5,7,9] | ||
| - | Prelude | + | Prelude> [True, False, True] |
[True,False,True] | [True,False,True] | ||
Strings are just lists of characters. | Strings are just lists of characters. | ||
| - | Prelude | + | 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 <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 | + | 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 | + | Prelude> (1, True) |
(1,True) | (1,True) | ||
| - | Prelude | + | 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 185: | Line 186: | ||
The types are probably what you'd expect. | The types are probably what you'd expect. | ||
| - | Prelude> :t | + | Prelude> :t ['a' .. 'c'] |
| - | + | ['a' .. 'c'] :: [Char] | |
| - | Prelude> :t | + | 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. | Lists are used a lot in Haskell. There are several functions that do nice things with them. | ||
| - | Prelude | + | Prelude> [1 .. 5] |
| - | + | [1,2,3,4,5] | |
| - | Prelude | + | Prelude> map (+ 2) [1 .. 5] |
| - | + | [3,4,5,6,7] | |
| - | Prelude | + | Prelude> filter (> 2) [1 .. 5] |
| - | + | [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 | + | Prelude> fst (1, 2) |
| - | + | 1 | |
| - | Prelude | + | Prelude> snd (1, 2) |
| - | + | 2 | |
| - | Prelude | + | Prelude> map fst [(1, 2), (3, 4), (5, 6)] |
| - | + | [1,3,5] | |
| + | |||
| + | Also see [[how to work on lists]] | ||
| - | == Function | + | == [[Function]] definitions == |
| - | We wrote a | + | We wrote a definition of an [[Introduction to Haskell IO/Actions |IO action]] earlier, called <hask>main</hask>: |
<haskell> | <haskell> | ||
| Line 220: | Line 223: | ||
</haskell> | </haskell> | ||
| - | + | Now, let's supplement it by actually writing a ''[[function]]'' definition and call it <hask>factorial</hask>. I'm also adding a module header, which is good form. | |
<haskell> | <haskell> | ||
| Line 243: | Line 246: | ||
There's a function. Just like the built-in functions, it can be called as <hask>factorial 5</hask> without needing parentheses. | 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. | + | Now ask <tt>ghci</tt> for the [[type]]. |
$ ghci Test.hs | $ ghci Test.hs | ||
<< GHCi banner >> | << GHCi banner >> | ||
Ok, modules loaded: Main. | Ok, modules loaded: Main. | ||
| - | Prelude Main> :t | + | Prelude Main> :t factorial |
| - | + | factorial :: (Num a) => a -> a | |
| - | Function types are written with the argument type, | + | Function types are written with the argument type, then <hask> -> </hask>, then the result type. (This also has the type class <hask>Num</hask>.) |
Factorial can be simplified by writing it with case analysis. | Factorial can be simplified by writing it with case analysis. | ||
| Line 260: | Line 263: | ||
</haskell> | </haskell> | ||
| - | == Convenient | + | == Convenient syntax == |
| - | A couple extra pieces of syntax are helpful. | + | A couple extra pieces of [[:Category:Syntax |syntax]] are helpful. |
<haskell> | <haskell> | ||
| Line 268: | Line 271: | ||
perHour = 60 * perMinute | perHour = 60 * perMinute | ||
perDay = 24 * perHour | perDay = 24 * perHour | ||
| - | perWeek = 7 * | + | perWeek = 7 * perDay |
| - | in secs | + | in secs / perWeek |
</haskell> | </haskell> | ||
| - | The <hask>let</hask> | + | The <hask>let</hask> expression defines temporary names. (This is using layout again. You could use {braces}, and separate the names with semicolons, if you prefer.) |
<haskell> | <haskell> | ||
| Line 281: | Line 284: | ||
</haskell> | </haskell> | ||
| - | The <hask>case</hask> | + | The <hask>case</hask> expression does a multi-way branch. The special label <hask>_</hask> means "anything else". |
| - | == Using | + | == 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. | |
| - | * Useful data structures | + | The best road from here to becoming a very productive Haskell programmer (aside from practice!) is becoming familiar with other [[Applications and libraries | libraries]] that do the things you need. Documentation on the standard libraries is at [http://haskell.org/ghc/docs/latest/html/libraries/ http://haskell.org/ghc/docs/latest/html/libraries/]. There are modules there with: |
| - | * Concurrent and parallel programming | + | |
| - | * Graphics and GUI libraries | + | * [[Applications and libraries/Data structures |Useful data structures]] |
| - | * Networking, POSIX, and other system-level stuff | + | * [[Applications and libraries/Concurrency and parallelism |Concurrent and parallel programming]] |
| + | * [[Applications and libraries/GUI libraries | Graphics and GUI libraries]] | ||
| + | * [[Applications and libraries/Network | Networking, POSIX, and other system-level stuff]] | ||
* Two test frameworks, QuickCheck and HUnit | * Two test frameworks, QuickCheck and HUnit | ||
* Regular expressions and predictive parsers | * Regular expressions and predictive parsers | ||
| Line 298: | Line 303: | ||
module Main where | module Main where | ||
| - | import Data.Map as M | + | import qualified Data.Map as M |
errorsPerLine = M.fromList | errorsPerLine = M.fromList | ||
| Line 313: | Line 318: | ||
The <hask>import</hask> says to use code from <hask>Data.Map</hask> and that it will be prefixed by <hask>M</hask>. (That's necessary because some of the functions have the same names as functions from the prelude. Most libraries don't need the <hask>as</hask> part.) | The <hask>import</hask> says to use code from <hask>Data.Map</hask> and that it will be prefixed by <hask>M</hask>. (That's necessary because some of the functions have the same names as functions from the prelude. Most libraries don't need the <hask>as</hask> part.) | ||
| - | If you want something that's not in the standard library, try looking at | + | 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 configure | ||
| Line 321: | Line 326: | ||
On a UNIX system, you may need to be root for that last part. | On a UNIX system, you may need to be root for that last part. | ||
| - | == Topics | + | == Topics that don't fit in 10 minute limit == |
| - | * Advanced | + | * [[:Category:Language | Advanced data types]] |
| - | ** Arithmetic | + | ** Arithmetic lists |
| - | ** List | + | ** [[List comprehension]]s |
| - | ** Type | + | ** [[Type#Type and newtype | Type synonyms]] |
| - | ** | + | ** [[Type|data vs newtype]] (and [[Newtype|here]]) |
| - | ** Type | + | ** [[Class |Type classes and instances]] |
| - | * | + | * [[:Category:Syntax |Advanced syntax]] |
| - | ** | + | ** [[Operator]]s |
| - | ** (+) and `foo` | + | ** [[Infix operator |(+) and `foo`]] |
| - | ** Fixity | + | ** [[Fixity declaration]]s |
| - | * Advanced | + | * Advanced functions |
| - | ** Currying | + | ** [[Currying]] |
| - | ** | + | ** [[Lambda abstraction]]s |
| - | ** Sections | + | ** [[Section of an infix operator |Sections]] |
| - | * Monads | + | * [[:Category:Monad |Monads]] |
| - | * File I/O | + | * [[Tutorials/Programming Haskell/String IO |File I/O]] |
** Reading files | ** Reading files | ||
** Writing Files | ** Writing Files | ||
| + | |||
| + | [[Category:Tutorials]] | ||
| + | Languages: [[Learn Haskell in 10 minutes|en]] [[Cn/十分钟学会 Haskell|zh/cn]] [[10分で学ぶHaskell|ja]] [[Haskell em 10 minutos|pt]] | ||
Current revision
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) 16Strings 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) TrueThe
Prelude> do { putStr "2 + 2 = " ; print (2 + 2) }
2 + 2 = 4
Prelude> do { putStrLn "ABCDE" ; putStrLn "12345" }
ABCDE
12345
Reading can be done with Prelude> do { n <- readLn ; print (n^2) }
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. 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 usePrelude> 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,
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:
- can be used as any numeric type. (This is why I was able to declare42as either an5or aIntearlier.)Double
- can be any fractional type, but not an integral type.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
- is a fraction type, with no rounding error.Rational
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 Prelude> () () Prelude> :t () () :: ()You can think of this as similar to the void keyword in C family languages. You can return
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
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
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, 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 factorial :: (Num a) => a -> aFunction types are written with the argument type, then
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
classify age = case age of 0 -> "newborn" 1 -> "infant" 2 -> "toddler" _ -> "senior citizen"
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:
- Useful data structures
- Concurrent and parallel programming
- Graphics and GUI libraries
- Networking, POSIX, and other system-level stuff
- Two test frameworks, QuickCheck and HUnit
- Regular expressions and predictive parsers
- More...
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
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
- Advanced data types
- Arithmetic lists
- List comprehensions
- Type synonyms
- data vs newtype (and here)
- Type classes and instances
- Advanced syntax
- Advanced functions
- Monads
- File I/O
- Reading files
- Writing Files
