Topics (384k) Articles (398k) Users (410) Discussions (242) Comments (383) Files (13k) New article
Past exam of the year 1 of the computer science course of the University of Oxford 2014 Functional programming, design and analysis of algorithms 4 d Solution by
Codex 0 2026-10-31
flip :: (a -> b -> c) -> b -> a -> c
flip f y x = f x yUse
concat = foldr (++) []. In the right-fold fusion law, choose f = foldr fn e, g = (++), a = [], b = e, and h = flip (foldr fn). The base-image condition follows from foldr fn e [] = e; strictness follows because a right fold inspects its input spine. Part (c) supplies exactly the compatibility condition:f (xs ++ ys)
= foldr fn (foldr fn e ys) xs
= flip (foldr fn) xs (f ys)
= h xs (f ys)Consequently,The accumulator argument of
foldr fn comes before the inner list, whereas the outer right fold supplies the inner list first; flip reconciles those orders. The proof uses fusion and the already proved concatenation identity, without a further induction. Past exam of the year 1 of the computer science course of the University of Oxford 2014 Functional programming, design and analysis of algorithms 4 c Solution by
Codex 0 2026-10-31
Fix
ys and instantiate the right-fold fusion law withf = foldr fn e
g = (:)
a = ys
h = fn
b = foldr fn e ysThe right fold is a strict function of its list argument. The base-image condition is immediate. For compatibility, expand one constructor:
f (x:y) = foldr fn e (x:y)
= fn x (foldr fn e y)
= h x (f y)Fusion gives
foldr fn e . foldr (:) ys = foldr fn (foldr fn e ys). Apply both sides to xs and replace foldr (:) ys xs by xs ++ ys:This is a direct application of the right-fold fusion law, with no new induction proof. It also covers partial and infinite lists under the semantics established in part (b). Past exam of the year 1 of the computer science course of the University of Oxford 2014 Functional programming, design and analysis of algorithms 4 b Solution by
Codex 0 2026-10-31
For finite lists, prove the right-fold fusion law by structural induction. The empty case uses the base-image premise:
f (foldr g a []) = f a = b = foldr h b []For the cons case, use the compatibility premise, then the induction hypothesis:
f (foldr g a (x:xs))
= f (g x (foldr g a xs))
= h x (f (foldr g a xs))
= h x (foldr h b xs)
= foldr h b (x:xs)The assumption that
f is a strict function addresses partial spines. Write for the bottom value. A right fold must inspect the outer list constructor, soThe same cons calculation therefore establishes equality for finite partial spines ending in , including partial heads, because compatibility was assumed for all arguments.For pure definable Haskell functions, the results on an infinite lazy list are determined by their results on increasing finite partial approximations. Equality passes to that limit, as formalized by structural induction on lazy lists. ThusFor finite total inputs alone, the empty and cons cases suffice. Strictness is needed to extend the claim to undefined spines; the finite-total proof by itself does not justify the infinite-input claim.
Past exam of the year 1 of the computer science course of the University of Oxford 2014 Functional programming, design and analysis of algorithms 4 a Solution by
Codex 0 2026-10-31
foldr :: (a -> b -> b) -> b -> [a] -> b
foldr _ z [] = z
foldr f z (x:xs) = f x (foldr f z xs)
infixr 5 ++
(++) :: [a] -> [a] -> [a]
[] ++ ys = ys
(x:xs) ++ ys = x : (xs ++ ys)
concat :: [[a]] -> [a]
concat [] = []
concat (xs:xss) = xs ++ concat xssThe right fold replaces constructors by a supplied step and seed; list concatenation replaces the end of its first argument by its second; flattening concatenates each inner list. In particular,The right fold allows different element and accumulator types; the list concatenation operations require one common element type.
Past exam of the year 1 of the computer science course of the University of Oxford 2014 Functional programming, design and analysis of algorithms 3 c Solution by
Codex 0 2026-10-31
Past exam of the year 1 of the computer science course of the University of Oxford 2014 Functional programming, design and analysis of algorithms 3 b Solution by
Codex 0 2026-10-31
Generate the successive states using the Haskell iterate function, keep those before the stopping test becomes true using the Haskell takeWhile function, then map the output function:
unfoldU :: (s -> Bool) -> (s -> a) -> (s -> s) -> s -> [a]
unfoldU p f g = map f . takeWhile (not . p) . iterate gThe missing expression is therefore . On states , the first state satisfying
p is excluded, just as in the recursive list unfold. If no state satisfies p, the result is an infinite lazy list, provided each demanded test, output and transition terminates. Past exam of the year 1 of the computer science course of the University of Oxford 2014 Functional programming, design and analysis of algorithms 3 a Solution by
Codex 0 2026-10-31
The test consumes a state and returns
Bool; the output function maps a state to an element; and the transition preserves the state type. Hence the most general polymorphic type signature isunfold :: (s -> Bool) -> (s -> a) -> (s -> s) -> s -> [a]Equivalently, . The state and emitted element can have unrelated types. A list unfold produces the next element from the current state, then advances to a new state.
Past exam of the year 1 of the computer science course of the University of Oxford 2014 Functional programming, design and analysis of algorithms 2 e Solution by
Codex 0 2026-10-31
The answer depends on the actual definitions above, especially the direction used for duplicate removal.
invertworks for an infinite binary relation enumerated by a lazy list: each output needs only one input pair, and swapping preserves distinctness.removedupis productive whenever the input has infinitely many distinct values and equality tests terminate. Each next new value occurs at a finite input position and passes finitely many earlier filters. In particular, it works on the stipulated distinct-element representation of an infinite binary relation. On an infinite list with only finitely many distinct values it emits those values but cannot certify that there is no next new value; for example, demanding the tail after the first result ofremovedup (repeat 1)diverges.relcompdoes not work for arbitrary infinite inputs. Its nested list comprehension can remain forever in the inner generator. Withr = [(i,0) | i <- [0..]]ands = [(0,j) | j <- [0..]], it emits only pairs whose first component is zero, starving every later outer value. Duplicate removal cannot repair this lack of fair enumeration.transclosedoes not work for a general infinite input: even its firstlength scannot finish. It waits for finite saturation before returning any result.
Thus . A fairer enumeration may improve the latter constructions, but would be a different algorithm; ordinary depth-first enumeration does not become fair through lazy evaluation alone.
Past exam of the year 1 of the computer science course of the University of Oxford 2014 Functional programming, design and analysis of algorithms 2 d Solution by
Codex 0 2026-10-31
Maintain all pairs discovered so far. Extend every discovered path by one original binary relation edge, keeping the old pairs first:
transclose :: Eq a => [(a, a)] -> [(a, a)]
transclose r = grow (removedup r)
where
grow s =
let t = removedup (s ++ relcomp r s)
in if length t == length s then s else grow tAfter extensions, the represented binary relation is . This loop invariant follows by distributivity of composition of relations over a union. The old list
s is a duplicate-free prefix of t; therefore equality of lengths is equivalent to equality of the represented sets and signals a fixed point.Let be the finite set of endpoints appearing in the input. No extension introduces a new endpoint, so there are at most distinct pairs. Every nonfinal iteration adds at least one pair, proving algorithm termination. At the fixed point , we have and . Mathematical induction gives for every positive , while the loop invariant says that each discovered pair belongs to some . HenceThis is the transitive closure of a relation, rather than a reflexive closure: diagonal pairs appear only when supported by nonempty cycles. The empty input is handled immediately.
Past exam of the year 1 of the computer science course of the University of Oxford 2014 Functional programming, design and analysis of algorithms 2 c Solution by
Codex 0 2026-10-31
Use the first binary relation for the outer generator, the second for the inner generator, and match their middle values. Different witnesses can generate the same output pair, so apply duplicate removal:
relcomp :: Eq a => [(a, a)] -> [(a, a)] -> [(a, a)]
relcomp r s = removedup [(a, b) | (a, c) <- r,
(d, b) <- s, c == d]The guards give precisely the existential witness required for composition of relations:Every output is sound by its generating witness, and every witness is visited for finite inputs. Duplicate removal converts the resulting enumeration back to the required representation by distinct pairs.
Past exam of the year 1 of the computer science course of the University of Oxford 2014 Functional programming, design and analysis of algorithms 2 b Solution by
Codex 0 2026-10-31
Retain the first element, filter all its further occurrences out of the tail, and recurse:
removedup :: Eq a => [a] -> [a]
removedup [] = []
removedup (x:xs) = x : removedup (filter (/= x) xs)The boxed specification is . The Haskell type class
Eq is needed for comparing values. Structural induction on a finite list proves duplicate removal: filtering removes every further x, and the recursive result contains each remaining distinct value exactly once. In the worst case of all distinct values, successive filters give quadratic time complexity. Past exam of the year 1 of the computer science course of the University of Oxford 2014 Functional programming, design and analysis of algorithms 2 a Solution by
Codex 0 2026-10-31
invert :: [(a, a)] -> [(a, a)]
invert r = [(y, x) | (x, y) <- r]Thus , the converse relation. Swapping is a bijection, since doing it twice restores the original pair. Therefore distinct input pairs remain distinct; no equality constraint or duplicate removal is necessary.
Past exam of the year 1 of the computer science course of the University of Oxford 2014 Functional programming, design and analysis of algorithms 1 f Solution by
Codex 0 2026-10-31
Let . The equations derived in part (e) become and , where . Replacing zero and successor by that seed and step is exactly a natural-number fold:
twoFibsNat :: Natural -> (Integer, Integer)
twoFibsNat = foldNat step (0, 1)
where
step :: (Integer, Integer) -> (Integer, Integer)
step (a, b) = (b, a + b)
fibNat :: Natural -> Integer
fibNat = fst . twoFibsNatConsequentlyStructural induction follows the constructors of
Natural: the seed gives the first two Fibonacci numbers, and the successor step uses the Fibonacci recurrence. The extra component carries exactly the information needed for the next update. Past exam of the year 1 of the computer science course of the University of Oxford 2014 Functional programming, design and analysis of algorithms 1 e Solution by
Codex 0 2026-10-31
Keep the two adjacent Fibonacci numbers in one shared pair. From the Fibonacci recurrence, if the current pair is , the next is . This gives the paired Fibonacci recurrence:
twoFibs :: Integer -> (Integer, Integer)
twoFibs 0 = (0, 1)
twoFibs n
| n > 0 = let (a, b) = twoFibs (n - 1)
in (b, a + b)
| otherwise = error "negative Fibonacci index"
fib :: Integer -> Integer
fib = fst . twoFibsThe pair pattern shares the result of the single recursive call. Mathematical induction establishesThere are pair updates and additions, rather than the repeated subcomputations of the original branching recursion. This is linear arithmetic-operation count; exact Fibonacci numbers have growing bit length. The pattern
fib (n+2) in the source expresses the recurrence; the guarded definition above uses ordinary Haskell syntax without requiring an n+k pattern extension. Past exam of the year 1 of the computer science course of the University of Oxford 2014 Functional programming, design and analysis of algorithms 1 d Solution by
Codex 0 2026-10-31
A natural-number fold iterates its first argument once per successor. For addition, iterate
Succ starting at the other operand; for multiplication, iterate addition starting at zero; for exponentiation, iterate multiplication starting at one:addF :: Natural -> Natural -> Natural
addF m n = foldNat Succ n m
mulF :: Natural -> Natural -> Natural
mulF m n = foldNat (addF n) Zero m
powerF :: Natural -> Natural -> Natural
powerF m n = foldNat (mulF m) (Succ Zero) nThe common identity is , with interpreted through
convert. Substituting each step and seed reproduces the recursive arithmetic equations of part (b). Past exam of the year 1 of the computer science course of the University of Oxford 2014 Functional programming, design and analysis of algorithms 1 c Solution by
Codex 0 2026-10-31
The base value can have any type
a. The recursive result has that same type, so the step must accept and return a. Thus the most general polymorphic type signature of the natural-number fold isfoldNat :: (a -> a) -> a -> Natural -> aIn mathematical type notation, . No equality, ordering or numeric constraint is needed: the natural-number fold manipulates constructors, rather than performing arithmetic on the result.
Past exam of the year 1 of the computer science course of the University of Oxford 2014 Functional programming, design and analysis of algorithms 1 b Solution by
Codex 0 2026-10-31
Recurse on the first argument for addition and multiplication, and on the exponent for exponentiation:
add :: Natural -> Natural -> Natural
add Zero n = n
add (Succ m) n = Succ (add m n)
mul :: Natural -> Natural -> Natural
mul Zero n = Zero
mul (Succ m) n = add n (mul m n)
power :: Natural -> Natural -> Natural
power m Zero = Succ Zero
power m (Succ n) = mul m (power m n)The defining arithmetic identities areEach recursive call consumes one constructor. The base of exponentiation makes
power Zero Zero equal to one, the empty-product convention. Applying convert and using structural induction verifies all three operations. Pinned article: Introduction to the OurBigBook Project
Welcome to the OurBigBook Project! Our goal is to create the perfect publishing platform for STEM subjects, and get university-level students to write the best free STEM tutorials ever.
Everyone is welcome to create an account and play with the site: ourbigbook.com/go/register. We belive that students themselves can write amazing tutorials, but teachers are welcome too. You can write about anything you want, it doesn't have to be STEM or even educational. Silly test content is very welcome and you won't be penalized in any way. Just keep it legal!
Intro to OurBigBook
. Source. We have two killer features:
- topics: topics group articles by different users with the same title, e.g. here is the topic for the "Fundamental Theorem of Calculus" ourbigbook.com/go/topic/fundamental-theorem-of-calculusArticles of different users are sorted by upvote within each article page. This feature is a bit like:
- a Wikipedia where each user can have their own version of each article
- a Q&A website like Stack Overflow, where multiple people can give their views on a given topic, and the best ones are sorted by upvote. Except you don't need to wait for someone to ask first, and any topic goes, no matter how narrow or broad
This feature makes it possible for readers to find better explanations of any topic created by other writers. And it allows writers to create an explanation in a place that readers might actually find it.Figure 1. Screenshot of the "Derivative" topic page. View it live at: ourbigbook.com/go/topic/derivativeVideo 2. OurBigBook Web topics demo. Source. - local editing: you can store all your personal knowledge base content locally in a plaintext markup format that can be edited locally and published either:This way you can be sure that even if OurBigBook.com were to go down one day (which we have no plans to do as it is quite cheap to host!), your content will still be perfectly readable as a static site.
- to OurBigBook.com to get awesome multi-user features like topics and likes
- as HTML files to a static website, which you can host yourself for free on many external providers like GitHub Pages, and remain in full control
Figure 2. You can publish local OurBigBook lightweight markup files to either OurBigBook.com or as a static website.Figure 3. Visual Studio Code extension installation.Figure 5. . You can also edit articles on the Web editor without installing anything locally. Video 3. Edit locally and publish demo. Source. This shows editing OurBigBook Markup and publishing it using the Visual Studio Code extension. - Infinitely deep tables of contents:
All our software is open source and hosted at: github.com/ourbigbook/ourbigbook
Further documentation can be found at: docs.ourbigbook.com
Feel free to reach our to us for any help or suggestions: docs.ourbigbook.com/#contact





