Haskell Fast & Hard (Part 2)

As of March 2020, School of Haskell has been switched to read-only mode.

Essential Haskell

Kandinsky Gugg

I suggest you to skim this part. Think of it like a reference. Haskell has a lot of features. Many informations are missing here. Get back here if notation feels strange.

I use the symbol to state that two expression are equivalent. It is a meta notation, does not exists in Haskell. I will also use to show what is the return of an expression.

Notations

Arithmetic
3 + 2 * 6 / 3 ⇔ 3 + ((2*6)/3)
Logic
True || False ⇒ True
True && False ⇒ False
True == False ⇒ False
True /= False ⇒ True  (/=) is the operator for different
Powers
x^n     for n an integral (understand Int or Integer)
x**y    for y any kind of number (Float for example)

Integer have no limit except the capacity of your machine:

4^103
102844034832575377634685573909834406561420991602098741459288064

Yeah! And also rational numbers FTW! But you need to import the module Data.Ratio:

$ ghci
....
Prelude> :m Data.Ratio
Data.Ratio> (11 % 15) * (5 % 3)
11 % 9
Lists
[]                      ⇔ empty list
[1,2,3]                 ⇔ List of integral
["foo","bar","baz"]     ⇔ List of String
1:[2,3]                 ⇔ [1,2,3], (:) prepend one element
1:2:[]                  ⇔ [1,2]
[1,2] ++ [3,4]          ⇔ [1,2,3,4], (++) concatenate
[1,2,3] ++ ["foo"]      ⇔ ERROR String ≠ Integral
[1..4]                  ⇔ [1,2,3,4]
[1,3..10]               ⇔ [1,3,5,7,9]
[2,3,5,7,11..100]       ⇔ ERROR! I am not so smart!
[10,9..1]               ⇔ [10,9,8,7,6,5,4,3,2,1]
Strings

In Haskell strings are list of Char.

'a' :: Char
"a" :: [Char]
""  ⇔ []
"ab" ⇔ ['a','b'] ⇔  'a':"b" ⇔ 'a':['b'] ⇔ 'a':'b':[]
"abc" ⇔ "ab"++"c"

Remark: In real code you shouldn't use list of char to represent text. You should mostly use Data.Text instead. If you want to represent stream of ASCII char, you should use Data.ByteString.

Tuples

The type of couple is (a,b). Elements in a tuple can have different type.

-- All these tuple are valid
(2,"foo")
(3,'a',[2,3])
((2,"a"),"c",3)

fst (x,y)       ⇒  x
snd (x,y)       ⇒  y

fst (x,y,z)     ⇒  ERROR: fst :: (a,b) -> a
snd (x,y,z)     ⇒  ERROR: snd :: (a,b) -> b
Deal with parentheses

To remove some parentheses you can use two functions: ($) and (.).

-- By default:
f g h x         ⇔  (((f g) h) x)

-- the $ replace parenthesis from the $
-- to the end of the expression
f g $ h x       ⇔  f g (h x) ⇔ (f g) (h x)
f $ g h x       ⇔  f (g h x) ⇔ f ((g h) x)
f $ g $ h x     ⇔  f (g (h x))

-- (.) the composition function
(f . g) x       ⇔  f (g x)
(f . g . h) x   ⇔  f (g (h x))

Exercise:

Define correctly the selectWinX functions using only fst, snd and . in order to show win on each line.

selectWin1 = undefined
main = do
  print $ selectWin1 (1,"win") -- should return "win"
selectWin2 = undefined
main = do
  print $ selectWin2 (("win","no"),"not this one")
selectWin3 = undefined
main = do
  print $ selectWin3 (1,("no",("win","almost")))

Useful notations for functions

Just a reminder:

x :: Int            ⇔ x is of type Int
x :: a              ⇔ x can be of any type
x :: Num a => a     ⇔ x can be any type a
                      such that a belongs to Num type class
f :: a -> b         ⇔ f is a function from a to b
f :: a -> b -> c    ⇔ f is a function from a to (b→c)
f :: (a -> b) -> c  ⇔ f is a function from (a→b) to c

Defining the type of a function before its declaration isn't mandatory. Haskell infers the most general type for you. But it is considered a good practice to do so.

Infix notation

square :: Num a => a -> a
square x = x^2

Note ^ use infix notation. For each infix operator there its associated prefix notation. You just have to put it inside parenthesis.

square' x = (^) x 2

square'' x = (^2) x

We can remove x in the left and right side! It's called η-reduction.

square''' = (^2)

Note we can declare function with ' in their name. Here:

squaresquare'square''square '''

Tests

An implementation of the absolute function.

absolute :: (Ord a, Num a) => a -> a
absolute x = if x >= 0 then x else -x

Note: the if .. then .. else Haskell notation is more like the ¤?¤:¤ C operator. You cannot forget the else.

Another equivalent version:

absolute' x
    | x >= 0 = x
    | otherwise = -x

Notation warning: indentation is important in Haskell. Like in Python, a bad indentation could break your code!

square :: Num a => a -> a
square x = x^2
square' x = (^) x 2
square'' x = (^2) x
square''' = (^2)
absolute :: (Ord a, Num a) => a -> a
absolute x = if x >= 0 then x else -x
absolute' x
    | x >= 0 = x
    | otherwise = -x
-- show
main = do
      print $ square 10
      print $ square' 10
      print $ square'' 10
      print $ square''' 10
      print $ absolute 10
      print $ absolute (-10)
      print $ absolute' 10
      print $ absolute' (-10)
-- /show

Exercise:

Modify the following code in order to use only prefix notation:

f x y = x*x + y*y
main = print $ f 2 4

continue to next part

comments powered by Disqus