Dynamic programming describes a problem by reusable subproblem states and a recurrence, computing each required state once through memoization or a bottom-up order. Its benefit comes from sharing answers to overlapping subproblems.
The principle of optimality says that, after the information needed by a state has been fixed, the remaining part of an optimal solution is optimal for that state. Otherwise replacing it by a better subsolution would improve the whole solution. A correct state must retain every constraint that can affect later choices.
The balanced comparison tournament uses
so . The second-largest search compares direct losers, using comparisons. The record of contains at most direct losers, because loses before becoming the overall winner. Hence the third candidate set has size at most , requiring at most comparisons.
For , the complete comparison count is therefore
This is and therefore meets the requested bound. The defeat-record lists can be linked in constant local work per merge; flattening the final partition takes work. Thus the method also has linear overall running time under constant-cost key comparisons.
The first value is the tournament winner . Find the second value by taking the maximum of the direct-loser set , retaining its associated tournament record.
The third-largest value must have lost directly to either or : any other value is smaller and could not defeat it. Therefore it belongs to
Conversely, every value in is distinct from . Thus the third-largest value is . This is tournament selection of the three largest elements; it uses the retained defeat records while computing the requested three-part partition.
Three largest elements exist only for . With the paper's power-of-two assumption this means . The partition in part (b) remains meaningful for , but a third output cannot be supplied in that case.
Build a balanced comparison tournament, retaining the record of each value's direct defeats. A record stores a key and a list of records that it directly defeated:
tournament(S):
    if |S| = 1:
        return Node(the element of S, [])
    split S into equally sized L and R
    a = tournament(L)
    b = tournament(R)
    if a.key < b.key:
        exchange a and b
    prepend b to a.losers
    return a
There is one key comparison at each merge. Because is a set, all keys are distinct, so the greater winner is unambiguous. Retaining the losing record also retains its own earlier comparison history; it does not merely retain the losing root's value.
Let the returned root have value . Define
The second-largest value can only lose to , so it occurs among those direct losers. This proves the required partition and the exclusion of the second-largest value from the third part. For , the winner participates in exactly merges, so . The other part can be materialized by marking the original element identities in this list and scanning the original inputs, using additional operations without more comparisons between keys.
The standard three-case master theorem concerns
with constant base-case cost and eventually nonnegative . Put .
  • If for some , then .
  • If , then .
  • If for some and eventually for a constant , then .
In a divide-and-conquer algorithm, counts recursive subproblems, is their size, and accounts for splitting and combining. The comparison with identifies whether leaves, all levels, or the upper levels dominate the running time. The polynomial gap and the third case's regularity condition are part of this version of the theorem.
Enumerate by the hypotenuse and test finitely many shorter legs:
primitiveTriples :: [(Integer, Integer, Integer)]
primitiveTriples =
  [(a, b, c) |
     c <- [1..],
     b <- [1..c-1],
     a <- [1..b-1],
     a*a + b*b == c*c,
     gcd a (gcd b c) == 1]
The equality selects Pythagorean triples, and the greatest common divisor test makes them primitive. The bounds enforce , removing the duplicate obtained by exchanging the legs. Each fixed has a finite search, so the outer loop gives ascending hypotenuse order and reaches every qualifying triple. Infinite families supplied by Euclid's formula ensure that the stream has arbitrarily many outputs. Its first five entries are
[(3,4,5),(5,12,13),(8,15,17),(7,24,25),(20,21,29)]
Using Integer avoids overflow in the squared values. The construction prioritizes a direct correctness argument; it does not claim an optimal enumeration cost.
For the requested Int-typed operation, remove the first element as well as its later multiples:
sieve :: [Int] -> [Int]
sieve [] = []
sieve (p:xs) = [x | x <- xs, x `rem` p /= 0]
On its intended input, p is positive, so the remainder is defined. An arbitrary list headed by zero lies outside this convention.
To enumerate literally all prime numbers, use unbounded Integer arithmetic:
primes :: [Integer]
primes = go [2..]
  where
    go :: [Integer] -> [Integer]
    go [] = []
    go (p:xs) =
      p : go [x | x <- xs, x `rem` p /= 0]
At each stage, the smallest remaining number has no smaller prime divisor and is therefore prime. Removing its larger multiples preserves every later prime and removes any composite number once its least prime divisor is processed. Lazy evaluation makes each requested finite prefix available. This implements the given repeated-filtering form of the sieve of Eratosthenes. A bounded Int stream can only cover representable values; Integer supplies the all-primes interpretation.
Enumerate finite shells of constant coordinate sum:
triples :: [(Integer, Integer, Integer)]
triples =
  [(a, b, k-a-b) |
     k <- [0..],
     a <- [0..k],
     b <- [0..k-a]]
Here natural numbers include zero. Every generated coordinate is nonnegative. Conversely, a given triple occurs in exactly the shell and at exactly those loop indices . Each shell contains only finitely many triples, so every triple is reached after finitely many earlier outputs. This is fair enumeration, unlike nesting three unrestricted infinite lists. For the positive-integer convention, add one to each generated coordinate.
Lazy evaluation is evaluation by need: an expression is deferred until its value is demanded, and its computed value is shared for subsequent demands of the same suspended computation.
Its two key properties here are avoiding evaluation of unused expressions and sharing demanded computations. For example, the first component of (3, undefined) can be obtained without evaluating the second. A suspended expression is represented by a thunk; after evaluation its result can be reused. This supports productive infinite lists: take 5 [0..] demands only a finite prefix. It does not guarantee that a demanded computation terminates.
Attach zero-based indices before filtering:
findStates :: [State] -> String -> [(State, Integer)]
findStates states str =
  [(state, i) |
     (state, i) <- zip states [0..],
     isPrefix str state]
The zip function pairs each state with its position in the original sequence. The list comprehension retains exactly those pairs satisfying the prefix test, preserving their order and their original indices. The declared result makes [0..] a stream of Integer indices. An empty search string matches every state, including an empty state, because the empty list is a prefix of every list.
The principal type needs an equality type class constraint:
isPrefix :: Eq a => [a] -> [a] -> Bool
isPrefix [] _ = True
isPrefix (_:_) [] = False
isPrefix (x:xs) (y:ys) = x == y && isPrefix xs ys
The empty list is a prefix of every list, witnessed by the second list itself as the remaining suffix. A nonempty prefix cannot fit in the empty list. Otherwise the first elements must agree, and the remaining first list must be a prefix of the remaining second list. These cases prove correctness by structural induction on the candidate prefix. The Eq a constraint is required by x == y; no ordering constraint is needed.
Generate successive states lazily and take exactly their initial nonempty segment:
runSystem :: (State, [Rule]) -> [State]
runSystem (state, rules) =
  takeWhile (not . null) (iterate (step rules) state)
The iterate function starts with state itself and repeatedly applies step rules. The takeWhile function excludes the first empty state and everything after it. If the initial state is empty, the result is []. If the process never reaches an empty state, the answer is a potentially infinite list whose finite prefixes can be observed through lazy evaluation. No artificial maximum number of rewriting steps is introduced.
Apply one replacement to each original character and concatenate the results:
step :: [Rule] -> State -> State
step rules = concatMap (applyRule rules)
The concatMap operation combines a map function and list concatenation. Replacements occur in original-character order, so a character produced by a replacement is not processed again during the same step. This is parallel string rewriting. In particular step rules "" = "", with no rule lookup required for the empty state.
Collect the matching replacements and distinguish all three possible multiplicities:
applyRule :: [Rule] -> Char -> String
applyRule rules c =
  case [replacement | (key, replacement) <- rules, key == c] of
    []          -> error ("no rule for " ++ [c])
    [result]    -> result
    (_:_:_)     -> error ("multiple rules for " ++ [c])
The list comprehension selects precisely the rules whose left-hand character is c. A singleton is the required unique match. The third branch also rejects duplicate rules with identical right-hand sides: there are still two matching rules. Finiteness of the rule list makes the uniqueness test decidable. The returned replacement may itself be empty.
Maintain a stack of values of the complete subexpressions encountered so far, with the newest value at its head:
evalRP :: RPolish -> Int
evalRP = finish . foldl push []
  where
    push :: [Int] -> Elem -> [Int]
    push stack (Number n) = n : stack
    push (right:left:stack) (Operator op) =
      applyOp op left right : stack
    push _ (Operator _) = error "missing operand"

    finish :: [Int] -> Int
    finish [value] = value
    finish _       = error "malformed expression"
The left fold processes tokens in their order. A number pushes its own value; an operator replaces the two latest subexpression values by their combination. The top value is the right operand, so preserving the order in applyOp op left right is necessary for subtraction and division. Induction on the consumed token prefix proves this stack machine invariant. A complete valid expression finishes with exactly one value.
Use an auxiliary parser that returns both a value and the unconsumed suffix. The arithmetic helper is:
applyOp :: Op -> Int -> Int -> Int
applyOp Add x y = x + y
applyOp Sub x y = x - y
applyOp Mul x y = x * y
applyOp Div x y = x `div` y
For the integer-valued expression language, this chooses integer division with div's rounding convention. The result is evaluated under the intended arithmetic model; bounded-Int overflow is separate from parsing.
evalP :: Polish -> Int
evalP input =
  case parse input of
    (value, []) -> value
    _           -> error "trailing tokens"
  where
    parse :: Polish -> (Int, Polish)
    parse [] = error "missing operand"
    parse (Number n : rest) = (n, rest)
    parse (Operator op : rest) =
      let (left, rest1)  = parse rest
          (right, rest2) = parse rest1
      in (applyOp op left right, rest2)
A number consumes one token. An operator consumes the two successive complete expressions that follow it, so nested operators are handled by recursion. Structural induction on the expression proves that parse consumes exactly its Polish notation and returns its value. Keeping the suffix is essential: neither operand has a fixed token count. Division by zero need not be treated separately under the stated input convention.
Pass an already constructed suffix through the traversal:
convert :: Expr -> RPolish
convert e = go e []
  where
    go :: Expr -> RPolish -> RPolish
    go (Num n) rest = Number n : rest
    go (App op left right) rest =
      go left (go right (Operator op : rest))
The invariant is that go e rest is the reverse Polish notation of e followed by rest. It holds at a numeric leaf. At an application, the result is the left subtree's tokens, then the right subtree's tokens, then the operator, then rest, exactly as required.
Each vertex of the abstract syntax tree creates one output list cell and performs constant local work. Thus producing the complete result takes time for an expression with vertices. No repeated list concatenation copies a previously traversed subtree. This suffix-passing construction is a difference list traversal.
Use a sum type whose two constructors distinguish a number from an operator:
data Elem = Number Int | Operator Op
Then the supplied Polish and RPolish aliases can both be lists of Elem. Constructor tags distinguish tokens without attempting to encode operators as special numeric values. The numeric type Int agrees with the supplied abstract syntax tree.
The expression parses as g . (g x). Initially write g :: a -> r and x :: a. In the function composition, g x must itself be a function whose result can be passed to g. Hence r = b -> a for a fresh type b, so
g :: a -> b -> a
g x :: b -> a
g . g x :: b -> b -> a
Consequently the principal type is
f :: (a -> b -> a) -> a -> b -> b -> a
One can check the constraints by expanding the composition:
f g x y z = g (g x y) z
Here g x y has type a, and the second application accepts it and the final b-typed argument z. The two type variables remain independent; no Haskell type class constraints are required.
Let x :: a and g :: a -> b, as required by the inner application g x. Using g x as the next argument of that same g forces b = a. Thus g (g x) :: a. Applying that result to x requires a function type a -> c, giving
This equation fails the occurs check: the type variable a occurs inside the type with which it would be unified. These constraints have no solution in the Hindley-Milner type system. Therefore the definition has no type in ordinary Haskell. The obstruction is to type inference, independently of which particular values might later be supplied.

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!
We have two killer features:
  1. 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-calculus
    Articles 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/derivative
  2. 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.
    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.
  3. https://raw.githubusercontent.com/ourbigbook/ourbigbook-media/master/feature/x/hilbert-space-arrow.png
  4. Infinitely deep tables of contents:
    Figure 6.
    Dynamic article tree with infinitely deep table of contents
    .
    Descendant pages can also show up as toplevel e.g.: ourbigbook.com/cirosantilli/chordate-subclade
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