Haskell:HaskellBasics
lastmod 2020-11-01created 2020-10-245 edits
Haskell Basics
Getting set up
- Download the Glasgow Haskell Compiler, i.e. GHC.
Variables and functions
- https://wikidocs.net/1570
- Comments:
--,{- ... -} - Variable:
r = 10 - Function:
area r = pi * r^2 -
whereclause:
Truth values
- https://wikidocs.net/1605
- Infix operators (e.g.
==): the following code is completely equivalent.
- Guards
- The absolute value function is as follows:
\(|x|=\begin{cases}x,&x\ge0\\-x,&x\lt0\end{cases}\) - The Haskell code is as follows:
- The absolute value function is as follows:
abs x
| x < 0 = 0 - x| otherwise = x
</syntaxhighlight>
-
- Notice how the code above is just as readable as the corresponding mathematical definition. Let's dissect the definition piece by piece.
- We start like a normal function definition, writing the function name abs and saying that it takes a single parameter x.
- Instead of writing
=and the right-hand side of the definition, we break the line and put the two alternatives on separate lines. These alternatives are what are called guards. The whitespace is not there just for aesthetic reasons; it is essential for the code to be parsed correctly. - Each guard begins with a pipe character,
|. After the pipe comes an expression that evaluates to a Boolean (also called a Boolean condition or a predicate), followed by the rest of the definition: the equals sign and the right-hand side to be used if the predicate evaluates to True. - The
otherwisebranch is used when none of the preceding predicates evaluates to True. In this case, if x is not less than 0, it must be equal to or greater than 0. So the last predicate could also have been written as x >= 0, butotherwiseworks just as well.
- Notice how the code above is just as readable as the corresponding mathematical definition. Let's dissect the definition piece by piece.
where and guards-
whereclauses are especially handy together with guards. A function that computes the number of (real) solutions of the quadratic equation \(ax2+bx+c=0\) is as follows:
numOfSolutions a b c
| disc > 0 = 2| disc == 0 = 1| otherwise = 0wheredisc = b^2 - 4*a*c
</syntaxhighlight>
Type basics
- 4 Type basics - WikibooksHaskell
- https://en.wikibooks.org/wiki/Haskell/Type_basics
- The command to check a type in GHCi is
:type(or:t):
Prelude> :type True True :: Bool
</syntaxhighlight>
- A character is
Char, and a string is[Char]. Note thatStringand[Char]are the same.
Prelude> :t 'H' 'H' :: Char Prelude> :t "Hello World" "Hello World" :: [Char]
- Function signatures:
- For example, checking the type of
xorprintsxor :: Bool -> Bool -> Bool. - The left side of
::is the function name. - The right side of
::is the list of the function's arguments, separated by the->symbol. - However, the type at the end after the last
->symbol is the return value.
- For example, checking the type of
let .. in: capitalize :: String -> String capitalize x =
let capWord [] = []capWord (x:xs) = toUpper x : xsin unwords (map capWord (words x))
</syntaxhighlight>
Lists and tuples
- 5 Lists and tuples - WikibooksHaskell
- Haskell/Lists and tuples - Wikibooks, open books for an open world
- Lists:
Prelude> let numbers = [1,2,3,4] Prelude> let truths = [True, False, False] Prelude> let strings = ["here", "are", "some", "strings"]
</syntaxhighlight>
- Square brackets delimit the list, and individual elements are separated by commas.
- The one important restriction is that all elements in a list must be of the same type.
- Trying to define a list with elements of mixed types results in a typical type error.
- Consing lists [^0]
-
[1,2,3,4,5]and1:2:3:4:5:[]are completely equivalent.- But there is a potential pitfall in building lists. Something like
True:False:[]is perfectly good Haskell code, butTrue:Falseis not.
- But there is a potential pitfall in building lists. Something like
- Strings are just lists too:
-
Prelude>"hey" == ['h','e','y'] True Prelude>"hey" == 'h':'e':'y':[] True
</syntaxhighlight>
- Tuples:
(True, 1) ("Hello world", False) (4, 5, "Six", True, 'b')
</syntaxhighlight>
-
- Tuples are immutable. That is, you cannot cons onto a tuple. So it makes sense to use tuples when you know in advance how many values will be stored.
- The elements of a tuple do not need to be of the same type.
References
Type basics II
- 6 Type basics II - WikibooksHaskell
- Haskell/Type basics II - Wikibooks, open books for an open world
If/patterns/let
- 7 Next steps - WikibooksHaskell
-
if/then/else:
mySignum x =
if x < 0then -1else if x > 0then 1else 0
</syntaxhighlight>
-
- It can easily be rewritten with guard syntax:
mySignum x
| x < 0 = -1| x > 0 = 1| otherwise = 0
</syntaxhighlight>
- Introducing pattern matching:
pts 1 = 10 pts 2 = 6 pts x
| x <= 6 = 7 - x| otherwise = 0
</syntaxhighlight>
-
- Another example:
(||) :: Bool -> Bool -> Bool False || False = False _ || _ = True
</syntaxhighlight>
- Tuple patterns and list patterns:
-- e.g.: head, tail, and patterns head :: [a] -> a head (x:_) = x head [] = error "Prelude.head: empty list"
tail :: [a] -> [a] tail (_:xs) = xs tail [] = error "Prelude.tail: empty list"
</syntaxhighlight>
-
letbindings- Put the
letkeyword before the declarations, and useinto signal that you are returning to the "main" body of the function. You can put several declarations inside a singlelet...inblock. Just make sure they are indented by the same amount, or you will get a syntax error:
- Put the
roots a b c =
let sdisc = sqrt (b*b - 4*a*c)twice_a = 2*ain ((-b + sdisc) / twice_a,(-b - sdisc) / twice_a)
</syntaxhighlight>
Building vocabulary
Use the function composition operator (.).