Learn Haskell in 10 minutes: Difference between revisions
No edit summary |
No edit summary |
||
Line 9: | Line 9: | ||
You can type most math expressions directly into ghci and get an answer. | You can type most math expressions directly into ghci and get an answer. | ||
Prelude> <hask>3 * 5</hask> | |||
15 | |||
Prelude> <hask>4 ^ 2 - 1</hask> | |||
15 | |||
Prelude> <hask>(1 - 5)^(3 * 2 - 4)</hask> | |||
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> | |||
"Hello" | |||
Prelude> <hask>"Hello" ++ ", Haskell"</hask> | |||
"Hello, Haskell" | |||
Calling functions is done by putting the arguments directly after the function. There are no parentheses as part of the function call: | Calling functions 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> | |||
6 | |||
Prelude> <hask>truncate 6.59</hask> | |||
6 | |||
Prelude> <hask>round 6.59</hask> | |||
7 | |||
Prelude> <hask>sqrt 2</hask> | |||
1.4142135623730951 | |||
Prelude> <hask>not (5 < 3)</hask> | |||
True | |||
Prelude> <hask>gcd 21 14</hask> | |||
7 | |||
== The Console == | == The Console == | ||
Line 42: | Line 42: | ||
I/O actions can be used to read from and write to the console. Some common ones include: | I/O actions can be used to read from and write to the console. Some common ones include: | ||
Prelude> <hask>putStrLn "Hello, Haskell"</hask> | |||
Hello, Haskell | |||
Prelude> <hask>putStr "No newline"</hask> | |||
No newlinePrelude> <hask>print (5 + 4)</hask> | |||
9 | |||
Prelude> <hask>print (1 < 2)</hask> | |||
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. The <hask>print</hask> function outputs any type of value. (If you <hask>print</hask> a string, it will have quotes around it.) | ||
Line 54: | Line 54: | ||
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> | |||
2 + 2 = 4 | |||
Prelude> <hask>do { putStrLn "ABCDE" ; putStrLn "12345" }</hask> | |||
ABCDE | |||
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 value 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 value to the result of an I/O action. | ||
Prelude> <hask>do { n <- readLn ; print (n^2) }</hask> | |||
4 | |||
16 | |||
(The 4 was input. The 16 was a result.) | (The 4 was input. The 16 was a result.) | ||
Line 86: | Line 86: | ||
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> | |||
5 | |||
Prelude> <hask>5 :: Double</hask> | |||
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. | 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 <hask>True</hask> | |||
<hask>True :: Bool</hask> | |||
Prelude> :t <hask>'X'</hask> | |||
<hask>'X' :: Char</hask> | |||
Prelude> :t <hask>"Hello, Haskell"</hask> | |||
<hask>"Hello, Haskell" :: [Char]</hask> | |||
(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 section on lists later.) | ||
Line 104: | Line 104: | ||
Things get more interesting for numbers. | Things get more interesting for numbers. | ||
Prelude> :t <hask>42</hask> | |||
<hask>42 :: (Num t) => t</hask> | |||
Prelude> :t <hask>42.0</hask> | |||
<hask>42.0 :: (Fractional t) => t</hask> | |||
Prelude> :t <hask>gcd 15 20</hask> | |||
<hask>gcd 15 20 :: (Integral t) => t</hask> | |||
These type signatures mean: | These type signatures mean: | ||
Line 117: | Line 117: | ||
* <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. | ||
The feature used here is "type classes". | The feature used here is "type classes". Types can be instances of type classes like <hask>Fractional</hask> or <hask>Integral</hask>. | ||
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 139: | Line 139: | ||
The final type worth mentioning here is <hask>()</hask>, pronounced "unit." It only has one value, also written as <hask>()</hask> and pronounced "unit." You can think of this as similar to the void 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. | The final type worth mentioning here is <hask>()</hask>, pronounced "unit." It only has one value, also written as <hask>()</hask> and pronounced "unit." You can think of this as similar to the void 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 == | |||
=== Lists === | |||
=== Common List Handling (map, filter, fold) === | |||
=== Tuples === | |||
=== Basic Tuple Functions (fst, snd) === | |||
== Function Definitions == | |||
=== Simple Functions === | |||
=== Function Types === | |||
=== Definition by Pattern Matching === | |||
=== Recursive Functions === | |||
== Syntax == | |||
=== Let === | |||
=== If/Then/Else === | |||
=== Case === | |||
== Using Library Stuff == | |||
=== Packages and Modules === | |||
=== Importing === | |||
=== Standard Library Haddock === | |||
=== Installing Stuff with Cabal === | |||
== Advanced Data Types == | |||
=== Arithmetic Lists === | |||
=== List Comprehensions === | |||
=== Type Synonyms === | |||
=== Data vs Newtype === | |||
=== Type Classes and Instances === | |||
== Advanced Syntax == | |||
=== Operators === | |||
=== (+) and `foo` === | |||
=== Fixity Declarations === | |||
== Advanced Functions == | |||
=== Currying === | |||
=== Lambdas === | |||
=== Sections === | |||
== Monads == | |||
== File I/O == | |||
=== Reading files === | |||
=== Writing Files === |
Revision as of 06:22, 13 July 2007
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.
Simple Expressions
You can type most math expressions directly into ghci and get an answer.
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
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 newlinePrelude>print (5 + 4)
9 Prelude>print (1 < 2)
True
The putStr
and putStrLn
functions output strings. 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 value 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
statement as a bonus.
Every line that starts in the same column as the first putStrLn
is part of 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.)
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
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> :tTrue
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> :t42
42 :: (Num t) => t
Prelude> :t42.0
42.0 :: (Fractional t) => t
Prelude> :tgcd 15 20
gcd 15 20 :: (Integral t) => t
These type signatures mean:
42
can be used as any numeric type. (This is why I was able to declare5<hask> as either an Int or a Double earlier.) * <hask>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.
The feature used here is "type classes". Types can be instances of type classes like Fractional
or Integral
.
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<hask> is a fraction type, with no rounding error. All five of these belong to the <hask>Num
type class. The first two belong toIntegral
, and the last two toFractional
.
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." You can think of this as similar to the void keyword in C family languages. You can return ()
from a function or I/O action if you don't want to return anything.