(.require
 [library
  [lux (.except)
   ["$" documentation]
   [data
    [text (.only \n)
     ["%" \\format (.only format)]]]]]
 [\\library
  ["[0]" / (.use "[1]#[0]" monoid)]]
 ["[0]" /
  ["[1][0]" property]])

(`` (def .public documentation
      (List $.Documentation)
      (let [zipped (list ($.definition /.zipped
                           "Create list zippers with the specified number of input lists."
                           [(def zipped_2 (zipped 2))
                            (def zipped_3 (zipped 3))
                            (zipped_3 xs ys zs)
                            ((zipped 3) xs ys zs)])

                         ($.definition /.zipped_with
                           "Create list zippers with the specified number of input lists."
                           [(def zipped_with_2 (zipped_with 2))
                            (def zipped_with_3 (zipped_with 3))
                            (zipped_with_2 + xs ys)
                            ((zipped_with 2) + xs ys)])

                         ($.definition /.zipped_2)
                         ($.definition /.zipped_3)
                         ($.definition /.zipped_with_2)
                         ($.definition /.zipped_with_3))]
        (/.partial ($.module /._
                             "")

                   ($.definition /.mix)
                   ($.definition /.equivalence)
                   ($.definition /.hash)
                   ($.definition /.monoid)
                   ($.definition /.functor)
                   ($.definition /.apply)
                   ($.definition /.monad)
                   
                   ($.definition /.first)
                   ($.definition /.after)
                   ($.definition /.while)
                   ($.definition /.until)
                   ($.definition /.every?)
                   ($.definition /.any?)

                   ($.definition /.mixes
                     ""
                     [(mixes f init inputs)])

                   ($.definition /.reversed
                     ""
                     [(reversed xs)])

                   ($.definition /.only
                     "A list with only values that satisfy the predicate."
                     [(only keep? xs)])

                   ($.definition /.partition
                     "Divide the list into all elements that satisfy a predicate, and all elements that do not."
                     [(partition satisfies? list)])

                   ($.definition /.pairs
                     "Cut the list into pairs of 2."
                     [(pairs list)])

                   ($.definition /.split_at
                     ""
                     [(split_at n xs)])

                   ($.definition /.split_when
                     "Segment the list by using a predicate to tell when to cut."
                     [(split_when predicate xs)])

                   ($.definition /.sub
                     "Segment the list into sub-lists of (at most) the given size."
                     [(sub size list)])

                   ($.definition /.repeated
                     "A list of the value x, repeated n times."
                     [(repeated n x)])

                   ($.definition /.iterations
                     "Generates a list element by element until the function returns .#None."
                     [(iterations f x)])

                   ($.definition /.one
                     ""
                     [(one check xs)])

                   ($.definition /.all
                     ""
                     [(all check xs)])

                   ($.definition /.example
                     "Yields the first value in the list that satisfies the predicate."
                     [(example predicate xs)])

                   ($.definition /.interposed
                     "Puts a value between every two elements in the list."
                     [(interposed sep xs)])

                   ($.definition /.size
                     ""
                     [(size list)])

                   ($.definition /.item
                     "Fetches the element at the specified index."
                     [(item i xs)])

                   ($.definition /.sorted
                     "A list ordered by a comparison function."
                     [(sorted < xs)])

                   ($.definition /.empty?
                     ""
                     [(empty? xs)])

                   ($.definition /.member?
                     ""
                     [(member? eq xs x)])

                   (,, (with_template [<name> <doc>]
                         [($.definition <name>
                            <doc>)]

                         [/.head "Yields the first element of a list."]
                         [/.tail "For a list of size N, yields the N-1 elements after the first one."]
                         ))

                   ($.definition /.indices
                     "Produces all the valid indices for a given size."
                     [(indices size)])

                   ($.definition /.last
                     ""
                     [(last xs)])

                   ($.definition /.inits
                     (format "For a list of size N, yields the first N-1 elements."
                             \n "Will yield a .#None for empty lists.")
                     [(inits xs)])

                   ($.definition /.together
                     "The sequential combination of all the lists.")

                   ($.definition /.with
                     "Enhances a monad with List functionality."
                     [(with monad)])

                   ($.definition /.lifted
                     "Wraps a monadic value with List machinery."
                     [(lifted monad)])

                   ($.definition /.enumeration
                     "Pairs every element in the list with its index, starting at 0."
                     [(enumeration xs)])

                   ($.definition /.when
                     "Can be used as a guard in (co)monadic be/do expressions."
                     [(do monad
                        [value (do_something 1 2 3)
                         .when (passes_test? value)]
                        (do_something_else 4 5 6))])

                   (all /#composite
                        zipped
                        
                        /property.documentation
                        )
                   ))))
