Skip to content
Search

Haskell:HaskellBasics

lastmod 2020-11-01created 2020-10-245 edits

Haskell Basics

Getting set up

Variables and functions

heron a b c = sqrt (s*(s-a)*(s-b)*(s-c))
    where
    s = (a+b+c) / 2

Truth values

Prelude> 4 + 9 == 13
True
Prelude> (==) (4 + 9) 13
True
  • 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:

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 otherwise branch 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, but otherwise works just as well.
  • where and guards
    • where clauses 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 = 0
where
disc = b^2 - 4*a*c

</syntaxhighlight>

Type basics

Prelude> :type True True :: Bool

</syntaxhighlight>

  • A character is Char, and a string is [Char]. Note that String and [Char] are the same.

Prelude> :t 'H' 'H' :: Char Prelude> :t "Hello World" "Hello World" :: [Char]

  • Function signatures:
    • For example, checking the type of xor prints xor :: 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.
  • Example of let .. in:

capitalize :: String -> String capitalize x =

let capWord []     = []
capWord (x:xs) = toUpper x : xs
in unwords (map capWord (words x))

</syntaxhighlight>

Lists and tuples

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] and 1: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, but True:False is not.
    • 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

If/patterns/let

mySignum x =

if x < 0
then -1
else if x > 0
then 1
else 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>

  • let bindings
    • Put the let keyword before the declarations, and use in to signal that you are returning to the "main" body of the function. You can put several declarations inside a single let...in block. Just make sure they are indented by the same amount, or you will get a syntax error:

roots a b c =

let sdisc = sqrt (b*b - 4*a*c)
twice_a = 2*a
in  ((-b + sdisc) / twice_a,
(-b - sdisc) / twice_a)

</syntaxhighlight>

Building vocabulary

Prelude> f a = a + a
Prelude> k x = x * x
Prelude> f (k 10)
200
Prelude> k (f 10)
400

Use the function composition operator (.).

Prelude> (f . k) 10
200
Prelude> (k . f) 10
400

Simple input and output

See also

author Zer0 sitemap