Basics
Recommended: Writing functions 2-4, 6 Challenging: Implementing (an approximate) Square Root
Syntax
How do x = 3
and x == 3
differ in meaning?
Evaluation
Given the following definitions:
= [x, x, x] thrice x : y : ys) = x : sums (x + y : ys) sums (x = xs sums xs
What does the expression
map thrice (sums [0 .. 4])
evaluate to? Write down the intermediate steps of your computation.A recursive function is only sensible if the value(s) of its parameters becomes simpler in each recursive application. Consider the following definition of the factorial function:
| n == 0 = 1 fac n | otherwise = n * fac (n − 1)
What happens if you evaluate
fac (−3)
?
Writing Functions
Write a function
noOfSol
that, for some \(a\), \(b\), and \(c\), determines the number of solutions of the equation \(ax^2 + bx + c = 0\), using case distinction.Write a function
pow2 :: Int -> Int
that takes an Int \(n\) computes \(2^n\) using direct recursion.pow2 :: Int -> Int 0 = 1 pow2 = 2 * pow2 (n - 1) pow2 n
Write a recursive function
pow
that takes two Ints, \(x\) and \(n\), and computes \(x^n\).For any number \(x\), and any even number \(n\) it holds that \(x^n = (x^{n/2})^2\). Use this to speed up the implementation of the
pow
function.pow :: Int -> Int -> Int `pow` 0 = 1 x `pow` n | even n = let y = x `pow` (n `div` 2) in y * y x | otherwise = x * (x `pow` (n-1))
Which intermediate results are being computed for the computation of
2 `pow` 10
in the old and the new definition?A predicate
p :: Int -> Bool
is monotonic if, for any Int i for which the predicate holds (p i == True
) the predicate also holds for any index j larger than i (p j
is alsoTrue
).Given:
- a monotonic predicate p,
- a lowerbound
l :: Int
for whichp l == False
, and - an upperbound
u :: Int
for whichp u == True
,
implement a function
binarySearch
that can find the smallest Inti
for whichp i
is True in \(O(\log (u - l))\) steps.Also give the type of your function.
binarySearch :: (Int -> Bool) -> Int -> Int -> Int | u - l == 1 = u binarySearch p l u | p h = binarySearch p l h | otherwise = binarySearch p h u where = (l + u) `div` 2 h
Give the most general type for the function
binarySearch
you defined above.binarySearch :: Integral i => (i -> Bool) -> i -> i -> i
Basic Types
Determine the types of
3
,even
, andeven 3
. How can you figure out the latter?Determine also the type of
head
,[1,2,3]
, andhead [1,2,3]
. What happens when applying a polymorphic function (like head) to monomorphic arguments (like[1,2,3]
)?Write down what you think the type of the following functions is. Do not use the interpreter (yet):
tail
,length
,noOfSol
,pow2
,div
,(/)
, andsqrt
?How can you query the interpreter for the type of an expression?
How can you explicitly specify the types of functions in your program?
Verify the types of the above expressions with the interpreter. If your answers differ, write down why you think that is the case.
Implementing (an approximate) Square Root
In this (set of) exercises we will write our own implementation of the
square root function. More precisely, we write a function approxSqrt
that can approximate \(\sqrt x\) for any value \(x\).
Consider the following two facts about the square root:
- if \(y\) is a good approximation of \(\sqrt{x}\) then \((1/2)(y+x/y)\) is a better approximation.
- \(1\) is a (not-so) good approximation of \(\sqrt{x}\)
We will say that the approximation of \(\sqrt{x}\) is good enough when \(y^2\) is close to \(x\). More specifically, when \(|y^2 - x|\) is at most some threshold \(\varepsilon\).
Use the above two facts to implement a function
approxSqrt :: Double -> Double -> Double
so thatapproxSqrt eps x
returns a value \(y\) that is a good enough (with respect to the given thresholdeps
).Hint: use an recursive helper function.
approxSqrt :: Double -> Double -> Double = go 1 approxSqrt eps x where = let y' = 0.5 * (y + x/y) go y in if goodEnough y then y' else go y' = abs (y*y - x) < eps goodEnough y
write an alternative implementation of
approxSqrt
using the following functionuntil :: (a -> Bool) -> (a -> a) -> a -> a
which takes care of the actual iteration/recursion.until stop f s | stop s = s | otherwise = until stop f (f s)
Starting with the value
s
,until stop f s
repeatedly applies the functionf
to get some new value until the predicatestop
returns True. Here are some examples:>>> let double x = 2*x in until (>1000) double 1 1024 >>> let double x = 2*x in until (>0) double 1 1
approxSqrt :: Double -> Double -> Double = until goodEnough refine 1 approxSqrt eps x where = abs (y*y - x) < eps goodEnough y = 0.5 * (y + x/y) refine y
Maybe we don’t know in advance yet when the approximation is “good enough”, and instead we just want a list of ever more precise approximations of \(\sqrt{x}\). Write a function
approxSqrts :: Double -> [Double]
that produces such a list.approxSqrts :: Double -> [Double] = go 1 approxSqrts x where = y : go (0.5 * (y + x/y)) go y -- or using the prelude function 'iterate': approxSqrts' :: Double -> [Double] = iterate refine 1 approxSqrts' x where = 0.5 * (y + x/y) refine y