on
Chapter 5: Types
This note captures my solutions to exercises in Chapter 5: Types of the book Haskell programming from first principles
Exercises: Type Matching
- The type signature for
notisBool -> Bool. - The type signature for
lengthis[a] -> Int. - The type signature for
concatis[[a]] -> [a]. - The type signature for
headis[a] -> a. - The type signature for
(<)isOrd a => a -> a -> Bool.
-- 1. a) not
not :: Bool -> Bool -- correct answer is 2. c)
-- 1. b) length
length :: [a] -> Int -- correct answer is 2. d)
-- 1. c) concat
concat :: [[a]] -> [a] -- correct answer is 2. b)
-- 1. d) head
head :: [a] -> a -- correct answer is 2. a)
-- 1. e) (<)
(<) :: Ord a => a -> a -> Bool -- correct answer is 2. e)
Exercises: Type Arguments
- If the type of
fisa -> a -> a -> a, and the type ofxisChar, then the type off xisChar -> Char -> Char. - If the type of
gisa -> b -> c -> b, then the type ofg 0 'c' "woot"isChar. - If the type of
his(Num a, Num b) => a -> b -> b, then the type ofh 1.0 2isNum b => b. - If the type of
his(Num a, Num b) => a -> b -> b, then the type ofh 1 (5.5 :: Double)isDouble. - If the type of
jackalis(Ord a, Eq b) => a -> b -> a, then the type ofjackal "keyboard" "has the word jackal in it"is[Char]. - If the type of
jackalis(Ord a, Eq b) => a -> b -> a, then the type ofjackal "keyboard"isEq b => b -> [Char]. - If the type of
kesselis(Ord a, Num b) => a -> b -> a, then the type ofkessel 1 2is(Num a, Ord a) => a. - If the type of
kesselis(Ord a, Num b) => a -> b -> a, then the type ofkessel 1 (2 :: Integer)is(Num a, Ord a) => a. - If the type of
kesselis(Ord a, Num b) => a -> b -> a, then the type ofkessel (1 :: Integer) 2isInteger.
Exercises: Parametricity
Given the type a -> a, which is the type for id, this function cannot do anything else other than returning the same type as that of the given value.
-- #1
f :: a -> a
f a = a
The type a -> a -> a has only two implementations.
-- #2
f :: a -> a -> a
f a b = a
f' :: a -> a -> a
f' a b = b
The type a -> b -> b can only have one implementation. The behavior changes when the types of b changes, but not when the type of a changes.
-- #3
f :: a -> b -> b
f a b = b
Exercises: Apply Yourself
Question 1
(++) :: [a] -> [a] -> [a]
myConcat :: [Char] -> [Char]
myConcat x = x ++ " yo"
The fully polymorphic type signature becomes concrete types [Char] -> [Char]
Question 2
(*) :: Num a => a -> a -> a
myMult :: Fractional a => a -> a
myMult x = (x / 3) * 5
The type signature Num a => a -> a -> a becomes constrained to Fractional a => a -> a signature. The numeric typeclass becomes further contrained to a fractional typeclass.
Question 3
take :: Int -> [a] -> [a]
myTake :: Int -> [Char]
myTake x = take x "hey you"
The type variable [a] becomes a concrete type [Char] because "hey you" has a type signature of [Char].
Question 4
(>) :: Ord a => a -> a -> Bool
myCom :: Int -> Bool
myCom x = x > (length [1..10])
The type variable a becomes a concrete type Int because length [1..10] has a type signature Int.
Question 5
(<) :: Ord a => a -> a -> Bool
myAlph :: Char -> Bool
myAlph x = x < 'z'
The type variable a becomes a concrete type Char because z has a concrete type Char.
Chapter Exercises
Multiple Choice
- (c) A value of type
[a]is a list whose elements are all of some typea. - (a) A function of type
[[a]] -> [a]could take a list of strings as an argument. - (b) A function of type
[a] -> Int -> areturns one element of typeafrom a list. - (c) A function of type
(a, b) -> atakes a tuple argument and returns the first value.
Determine the type
- (a)
(* 9) 6returns value :: type54 :: Num a => a - (b)
head [(0,"doge"),(1,"kitteh")]returns value :: type(0,"doge") :: Num a => (a, [Char]) - (c)
head [(0 :: Integer ,"doge"),(1,"kitteh")]returns value :: type(0,"doge") :: (Integer, [Char]) - (d)
if False then True else Falsereturns value :: typeFalse :: Bool - (e)
length [1, 2, 3, 4, 5]returns value :: type5 :: Int - (f)
(length [1, 2, 3, 4]) > (length "TACOCAT")returns value :: typeFalse :: Bool
{-# LANGUAGE NoMonomorphismRestriction #-}
module DetermineTheType where
example = 1
x :: Num a => a
x = 5
y :: Num a => a
y = x + 5
w :: Num a => a
w = y * 10
-- The type of `w` is `w :: Num a => a`
z :: Num a => a -> a
z y = y * 10
-- The type of `z` is `z :: Num a => a -> a`
f :: Fractional a => a
f = 4 / y
-- The type of `f` is `f :: Fractional a => a`
x' :: String
x' = "Julie"
y' :: String
y' = " <3 "
z' :: String
z' = "Haskell"
f' :: [Char]
f' = x' ++ y' ++ z'
-- The type of f` is `f :: [Char]`
Does it compile?
-- 1. `wahoo` breaks because `bigNum` is a value, not a function.
-- bigNum = (^) 5 $ 10
-- wahoo = bigNum $ 10
-- We can have the code below instead:
bigNum = (^ 5)
wahoo = bigNum 10
-- 2. This works. W
-- x = print
-- y = print "woohoo!"
-- z = x "hello world"
-- We can improve as shown below:
x = print
y = x "woohoo!"
z = x "hello world"
-- 3. `c` and `d` breaks because `b` is a value, not a function.
-- a = (+) b=5
-- c = b 10
-- d = c 200
-- We can use the code below instead:
a = (+)
b = 5
c = a b 10
d = a c 200
-- 4. `b` breaks because `c` is not in scope.
-- a = 12 + b
-- b = 10000 * c
-- I can fix by putting `c` in scope.
-- Order does not matter if code is in a source file.
-- In `GHCi`, I will need to define `c` first.
a' = 12 + b'
b' = 10000 * c'
c' = 1
Type Variable or Specific Type Constructor?
- In
f :: Num a => a -> b -> Int -> Int,ais constrained polymorphic (Num),bis fully polymorphic, andIntis a concrete type constructor. - In
f :: zed -> Zed -> Blah,zedis fully polymorphic,ZedandBlahare concrete type constructors. - In
f :: Enum b => a -> b -> C,ais fully polymorphic,bis constrained polymorphic (Enum), andCis a concrete type constructor. - In
f :: f -> g -> C,fandgare fully polymorphic andCis a concrete type constructor.
Write a type signature
module TypeSignature where
-- Write a Type Signature
functionH :: [a] -> a
functionH (x:_) = x
functionC :: Ord a => a -> a -> Bool
functionC x y = if (x > y) then True else False
functionS :: (a, b) -> b
functionS (x, y) = y
Given a type, write the function
module WriteTheFunction where
-- Given a Type, Write the Function
-- This is the same as the identify function `id`.
-- #1
i :: a -> a
i x = x
-- #2
c :: a -> b -> a
c x _ = x
-- `c` and `c''` are alpha equivalent.
-- #3
c'' :: b -> a -> b
c'' x _ = x
-- #4
c' :: a -> b -> b
c' _ y = y
-- There are multiple possibilities. These include:
-- #5
-- Tail function for a list
r :: [a] -> [a]
r (_:xs) = xs
r [] = []
-- Identity function for a list
r' :: [a] -> [a]
r' x = x
-- #6
co :: (b -> c) -> (a -> b) -> a -> c
co f g x = f (g x)
-- #7
a :: (a -> c) -> a -> a
a _ x = x
-- #8
a' :: (a -> b) -> a -> b
a' f x = f x
Fix it
module Sing where
fstString :: [Char] -> [Char]
fstString x = x ++ " in the rain"
sndString :: [Char] -> [Char]
sndString x = x ++ " over the rainbdow"
sing :: [Char] -> [Char] -> [Char]
sing x y = if (x > y) then fstString x else sndString y
where x = "Singin"
y = "Somewhere"
module Sing2 where
fstString :: [Char] -> [Char]
fstString x = x ++ " in the rain"
sndString :: [Char] -> [Char]
sndString x = x ++ " over the rainbdow"
sing :: [Char] -> [Char] -> [Char]
sing x y = if (x < y) then fstString x else sndString y
where x = "Singin"
y = "Somewhere"
module Arith3Broken where
main :: IO ()
main = do
print $ 1 + 2
putStrLn $ show 10
print (negate (-1))
print ((+) 0 blah)
where blah = negate 1
Type-Kwon-Do
module TypeKwonDo where
-- Type-Kwon-Do
data Woot
data Blah
f :: Woot -> Blah
f = undefined
g :: (Blah, Woot) -> (Blah, Blah)
g (b, w) = (b, f w)
-- 1. This is a composition `h x = g (f x)`.
f' :: Int -> String
f' = undefined
g' :: String -> Char
g' = undefined
h' :: Int -> Char
h' = g' . f'
-- 2. This is also a composition `e a = w (q a)`.
data A
data B
data C
q :: A -> B
q = undefined
w :: B -> C
w = undefined
e :: A -> C
e = w . q
-- 3. This accepts inputs `x` and `y` and uses the function `xz` and `yz`.
data X
data Y
data Z
xz :: X -> Z
xz = undefined
yz :: Y -> Z
yz = undefined
xform :: (X, Y) -> (Z, Z)
xform (x, y) = (xz x, yz y)
-- 4. This is another composition `munge f g x = fst (g (f x))`
munge :: (x -> y)
-> (y -> (w, z))
-> x
-> w
munge f g = fst . g . f