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
not
isBool -> Bool
. - The type signature for
length
is[a] -> Int
. - The type signature for
concat
is[[a]] -> [a]
. - The type signature for
head
is[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
f
isa -> a -> a -> a
, and the type ofx
isChar
, then the type off x
isChar -> Char -> Char
. - If the type of
g
isa -> b -> c -> b
, then the type ofg 0 'c' "woot"
isChar
. - If the type of
h
is(Num a, Num b) => a -> b -> b
, then the type ofh 1.0 2
isNum b => b
. - If the type of
h
is(Num a, Num b) => a -> b -> b
, then the type ofh 1 (5.5 :: Double)
isDouble
. - If the type of
jackal
is(Ord a, Eq b) => a -> b -> a
, then the type ofjackal "keyboard" "has the word jackal in it"
is[Char]
. - If the type of
jackal
is(Ord a, Eq b) => a -> b -> a
, then the type ofjackal "keyboard"
isEq b => b -> [Char]
. - If the type of
kessel
is(Ord a, Num b) => a -> b -> a
, then the type ofkessel 1 2
is(Num a, Ord a) => a
. - If the type of
kessel
is(Ord a, Num b) => a -> b -> a
, then the type ofkessel 1 (2 :: Integer)
is(Num a, Ord a) => a
. - If the type of
kessel
is(Ord a, Num b) => a -> b -> a
, then the type ofkessel (1 :: Integer) 2
isInteger
.
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 -> a
returns one element of typea
from a list. - (c) A function of type
(a, b) -> a
takes a tuple argument and returns the first value.
Determine the type
- (a)
(* 9) 6
returns 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 False
returns 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
,a
is constrained polymorphic (Num
),b
is fully polymorphic, andInt
is a concrete type constructor. - In
f :: zed -> Zed -> Blah
,zed
is fully polymorphic,Zed
andBlah
are concrete type constructors. - In
f :: Enum b => a -> b -> C
,a
is fully polymorphic,b
is constrained polymorphic (Enum
), andC
is a concrete type constructor. - In
f :: f -> g -> C
,f
andg
are fully polymorphic andC
is 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