{-
`fold` is the primitive function for consuming `List`s

If you treat the list `[ x, y, z ]` as `cons x (cons y (cons z nil))`, then a
`fold` just replaces each `cons` and `nil` with something else
-}
let fold
    :   ∀(a : Type)
      → List a
      → ∀(list : Type)
      → ∀(cons : a → list → list)
      → ∀(nil : list)
      → list
    = List/fold

let example0 =
        assert
      :   fold
            Natural
            [ 2, 3, 5 ]
            Natural
            (λ(x : Natural) → λ(y : Natural) → x + y)
            0
        ≡ 10

let example1 =
        assert
      :   (   λ(nil : Natural)
            → fold
                Natural
                [ 2, 3, 5 ]
                Natural
                (λ(x : Natural) → λ(y : Natural) → x + y)
                nil
          )
        ≡ (λ(nil : Natural) → 2 + (3 + (5 + nil)))

let example2 =
        assert
      :   (   λ(list : Type)
            → λ(cons : Natural → list → list)
            → λ(nil : list)
            → fold Natural [ 2, 3, 5 ] list cons nil
          )
        ≡ (   λ(list : Type)
            → λ(cons : Natural → list → list)
            → λ(nil : list)
            → cons 2 (cons 3 (cons 5 nil))
          )

in  fold
