{
  "title": "List operations",
  "level": "Low",
  "elements": [
    {
      "pattern": "Creating an empty list",
      "module": "List",
      "name": "empty",
      "type": "value",
      "signature": "val empty : 'a list",
      "description": "",
      "examples": []
    },
    {
      "pattern": "Checking if the list is empty",
      "module": "List",
      "name": "is_empty",
      "type": "function",
      "signature": "val is_empty : 'a list -> bool",
      "description": "Test whether a list is empty",
      "examples": []
    },
    {
      "pattern": "Adding an element to the beginning of a list (prepend)",
      "module": "List",
      "name": "cons",
      "type": "function",
      "signature": "val cons : 'a -> 'a list -> 'a list",
      "description": "cons x l prepends x to the beginning of l, returning a new list",
      "examples": []
    },
    {
      "pattern": "Creating a singleton list",
      "module": "List",
      "name": "return",
      "type": "value",
      "signature": "val return : 'a -> 'a list",
      "description": "Singleton list",
      "examples": []
    },
    {
      "pattern": "Getting the first element of a list",
      "module": "List",
      "name": "hd",
      "type": "function",
      "signature": "val hd : 'a list -> 'a",
      "description": "Partial function to access the head of the list. This function will fail when applied to the empty list. NOTE it is recommended to rely on pattern matching instead.",
      "examples": []
    },
    {
      "pattern": "Getting all but the first element of a list",
      "module": "List",
      "name": "tl",
      "type": "function",
      "signature": "val tl : 'a list -> 'a list",
      "description": "Partial function to access the tail of the list. This function will fail when applied to the empty list NOTE it is recommended to rely on pattern matching instead",
      "examples": []
    },
    {
      "pattern": "Concatenating two lists",
      "module": "List",
      "name": "append",
      "type": "function",
      "signature": "val append : 'a list -> 'a list -> 'a list",
      "description": "List append / concatenation. append l1 l2 returns a list composed of all elements of l1, followed by all elements of l2",
      "examples": []
    },
    {
      "pattern": "Axiom: For any list L, appending an empty list to L results in L itself.",
      "module": "List",
      "name": "append_to_nil",
      "type": "function",
      "signature": "val append_to_nil : 'a list -> bool",
      "description": "",
      "examples": [],
      "tags": ["theorem"]
    },
    {
      "pattern": "Axiom: For any element x, and lists L1 and L2, it's possible that appending x to L1 results in L2.",
      "module": "List",
      "name": "append_single",
      "type": "function",
      "signature": "val append_single : 'a -> 'a list -> 'a list -> bool",
      "description": "",
      "examples": [],
      "tags": ["theorem"]
    },
    {
      "pattern": "Reversing a list",
      "module": "List",
      "name": "rev",
      "type": "function",
      "signature": "val rev : 'a list -> 'a list",
      "description": "Reverse a list",
      "examples": []
    },
    {
      "pattern": "Calculating length of a list",
      "module": "List",
      "name": "length",
      "type": "function",
      "signature": "val length : 'a list -> Z.t",
      "description": "Compute the length of a list. Linear time.",
      "examples": []
    },
    {
      "pattern": "Axiom: List length is non-negative",
      "module": "List",
      "name": "len_nonnegative",
      "type": "function",
      "signature": "val len_nonnegative : 'a list -> bool",
      "description": "",
      "examples": [],
      "tags": ["theorem"]
    },
    {
      "pattern": "Axiom: Empty list has zero length",
      "module": "List",
      "name": "len_zero_is_empty",
      "type": "function",
      "signature": "val len_zero_is_empty : 'a list -> bool",
      "description": "",
      "examples": [],
      "tags": ["theorem"]
    },
    {
      "pattern": "Splitting a list of pairs into two lists",
      "module": "List",
      "name": "split",
      "type": "function",
      "signature": "val split : ('a * 'b) list -> 'a list * 'b list",
      "description": "Split a list of pairs into a pair of lists",
      "examples": []
    },
    {
      "pattern": "Applying a function to each element of a list",
      "module": "List",
      "name": "map",
      "type": "function",
      "signature": "val map : ( 'a -> 'b ) -> 'a list -> 'b list",
      "description": "Map a function over a list. \n - map f [] = []\n - map f [x] = [f x]\n - map f (x :: tail) = f x :: map f tail",
      "examples": []
    },
    {
      "pattern": "Applying a function to pairs of elements from two lists",
      "module": "List",
      "name": "map2",
      "type": "function",
      "signature": "val map2 : ( 'a -> 'b -> 'c ) -> 'a list -> 'b list -> ( 'c list, string ) result",
      "description": "",
      "examples": []
    },
    {
      "pattern": "for all: Checking if all elements of a list satisfy a predicate",
      "module": "List",
      "name": "for_all",
      "type": "function",
      "signature": "val for_all : ( 'a -> bool ) -> 'a list -> bool",
      "description": "for_all f l tests whether all elements of l satisfy the predicate f",
      "examples": []
    },
    {
      "pattern": "exists: Checking if any element of a list satisfies a predicate",
      "module": "List",
      "name": "exists",
      "type": "function",
      "signature": "val exists : ( 'a -> bool ) -> 'a list -> bool",
      "description": "exists f l tests whether there is an element of l that satisfies the predicate f",
      "examples": []
    },
    {
      "pattern": "applying a function to each element of a list from left to right and an accumulator, combining the results. (fold left)",
      "module": "List",
      "name": "fold_left",
      "type": "function",
      "signature": "val fold_left : ( 'a -> 'b -> 'a ) -> 'a -> 'b list -> 'a",
      "description": "Fold-left, with an accumulator that makes induction more challenging",
      "examples": [],
      "tags": ["higher-order function"]
    },
    {
      "pattern": "folding a list from right to left, without an accumulator. (fold right)",
      "module": "List",
      "name": "fold_right",
      "type": "function",
      "signature": "val fold_right : ( 'a -> 'b -> 'b ) -> base:'b -> 'a list -> 'b",
      "description": "Fold-right, without accumulator. This is generally more friendly for induction than fold_left.",
      "examples": [],
      "tags": ["higher-order function"]
    },
    {
      "pattern": "Mapping with index and base value",
      "module": "List",
      "name": "mapi_with",
      "type": "function",
      "signature": "val mapi_with : base:Z.t -> ( Z.t -> 'a -> 'b ) -> 'a list -> 'b list",
      "description": "",
      "examples": []
    },
    {
      "pattern": "Mapping with index",
      "module": "List",
      "name": "mapi",
      "type": "function",
      "signature": "val mapi : ( Z.t -> 'a -> 'b ) -> 'a list -> 'b list",
      "description": "",
      "examples": []
    },
    {
      "pattern": "Filtering elements of a list",
      "module": "List",
      "name": "filter",
      "type": "function",
      "signature": "val filter : ( 'a -> bool ) -> 'a list -> 'a list",
      "description": "filter f l keeps only the elements of l that satisfy f.",
      "examples": []
    },
    {
      "pattern": "Applying a filter and map function to a list",
      "module": "List",
      "name": "filter_map",
      "type": "function",
      "signature": "val filter_map : ( 'a -> 'b option ) -> 'a list -> 'b list",
      "description": "",
      "examples": []
    },
    {
      "pattern": "Applying a map function that returns lists and flattening the result",
      "module": "List",
      "name": "flat_map",
      "type": "function",
      "signature": "val flat_map : ( 'a -> 'b list ) -> 'a list -> 'b list",
      "description": "",
      "examples": []
    },
    {
      "pattern": "Finding an element of a list if it's present",
      "module": "List",
      "name": "find",
      "type": "function",
      "signature": "val find : ( 'a -> bool ) -> 'a list -> 'a option",
      "description": "find f l returns Some x if x is the first element of l such that f x is true. Otherwise it returns None",
      "examples": []
    },
    {
      "pattern": "Checking if an element is in a list",
      "module": "List",
      "name": "mem",
      "type": "function",
      "signature": "val mem : 'a -> 'a list -> bool",
      "description": "mem x l returns true iff x is an element of l",
      "examples": []
    },
    {
      "pattern": "Checking if a key is present in an association list",
      "module": "List",
      "name": "mem_assoc",
      "type": "function",
      "signature": "val mem_assoc : 'a -> ('a * 'b) list -> bool",
      "description": "",
      "examples": []
    },
    {
      "pattern": "Returns nth element in a list",
      "module": "List",
      "name": "nth",
      "type": "function",
      "signature": "val nth : Z.t -> 'a list -> 'a option",
      "description": "",
      "examples": []
    },
    {
      "pattern": "Finding a value associated with a key in an association list",
      "module": "List",
      "name": "assoc",
      "type": "function",
      "signature": "val assoc : 'a -> ('a * 'b) list -> 'b option",
      "description": "",
      "examples": []
    },
    {
      "pattern": "Returns the first n number of elements of a list as a list. A specific case of list slicing.",
      "module": "List",
      "name": "take",
      "type": "function",
      "signature": "val take : int -> 'a list -> 'a list",
      "description": "take n l returns a list composed of the first (at most) n elements of l. If length l <= n then it returns l",
      "examples": []
    },
    {
      "pattern": "Removes the first n number of elements in a list. A specific case of list slicing.",
      "module": "List",
      "name": "drop",
      "type": "function",
      "signature": "val drop : int -> 'a list -> 'a list",
      "description": "drop n l returns l where the first (at most) n elements have been removed. If length l <= n then it returns []",
      "examples": []
    },
    {
      "pattern": "Declaratively generate list of integers between two values (range)",
      "module": "List",
      "name": "(--)",
      "type": "function",
      "signature": "val (--) : int -> int -> int list",
      "description": "Integer range. i -- j is the list [i; i+1; i+2; …; j-1]. Returns the empty list if i >= j.",
      "examples": []
    },
    {
      "pattern": "Inserting element into a list so that it remains sorted",
      "module": "List",
      "name": "insert_sorted",
      "type": "function",
      "signature": "val insert_sorted : leq:( 'a -> 'a -> bool ) -> 'a -> 'a list -> 'a list",
      "description": "Insert x in l, keeping l sorted.",
      "examples": []
    },
    {
      "pattern": "Sorting a list",
      "module": "List",
      "name": "sort",
      "type": "function",
      "signature": "val sort : leq:( 'a -> 'a -> bool ) -> 'a list -> 'a list",
      "description": "Basic sorting function.",
      "examples": []
    },
    {
      "pattern": "Checking whether a list is sorted using a custom small-or-equal-than predicate",
      "module": "List",
      "name": "is_sorted",
      "type": "function",
      "signature": "val is_sorted : leq:( 'a -> 'a -> bool ) -> 'a list -> bool",
      "description": "Check whether a list is sorted, using the leq small-or-equal-than predicate",
      "examples": []
    },
    {
      "pattern": "Generating the Cartesian product of two lists",
      "module": "List",
      "name": "monoid_product",
      "type": "function",
      "signature": "val monoid_product : 'a list -> 'b list -> ('a * 'b) list",
      "description": "",
      "examples": []
    },
    {
      "pattern": "Applying a function to each element of a list (operator version)",
      "module": "List",
      "name": "(>|=)",
      "type": "function",
      "signature": "val (>|=) : 'a list -> ( 'a -> 'b ) -> 'b list",
      "description": "",
      "examples": []
    },
    {
      "pattern": "Applying a function that returns lists to each element and flattening the result (operator version)",
      "module": "List",
      "name": "(>>=)",
      "type": "function",
      "signature": "val (>>=) : 'a list -> ( 'a -> 'b list ) -> 'b list",
      "description": "",
      "examples": []
    },
    {
      "pattern": "Applying a function to each element of a list (monadic let syntax)",
      "module": "List",
      "name": "let+",
      "type": "function",
      "signature": "val let+ : 'a list -> ( 'a -> 'b ) -> 'b list",
      "description": "",
      "examples": []
    },
    {
      "pattern": "Combining two lists into a list of pairs (monadic and syntax)",
      "module": "List",
      "name": "and+",
      "type": "function",
      "signature": "val and+ : 'a list -> 'b list -> ('a * 'b) list",
      "description": "",
      "examples": []
    },
    {
      "pattern": "Applying a function that returns lists to each element and flattening the result (monadic let syntax)",
      "module": "List",
      "name": "let*",
      "type": "function",
      "signature": "val let* : 'a list -> ( 'a -> 'b list ) -> 'b list",
      "description": "",
      "examples": []
    },
    {
      "pattern": "Combining two lists into a list of pairs (monadic and syntax for bind)",
      "module": "List",
      "name": "and*",
      "type": "function",
      "signature": "val and* : 'a list -> 'b list -> ('a * 'b) list",
      "description": "",
      "examples": []
    }
  ],
  "metadata": {
    "signatures": [
      "val empty : 'a list",
      "val is_empty : 'a list -> bool",
      "val cons : 'a -> 'a list -> 'a list",
      "val return : 'a -> 'a list",
      "val hd : 'a list -> 'a",
      "val tl : 'a list -> 'a list",
      "val append : 'a list -> 'a list -> 'a list",
      "val rev : 'a list -> 'a list",
      "val length : 'a list -> Z.t",
      "val split : ('a * 'b) list -> 'a list * 'b list",
      "val map : ( 'a -> 'b ) -> 'a list -> 'b list",
      "val map2 : ( 'a -> 'b -> 'c ) -> 'a list -> 'b list -> ( 'c list, string ) result",
      "val for_all : ( 'a -> bool ) -> 'a list -> bool",
      "val exists : ( 'a -> bool ) -> 'a list -> bool",
      "val fold_left : ( 'a -> 'b -> 'a ) -> 'a -> 'b list -> 'a",
      "val fold_right : ( 'a -> 'b -> 'b ) -> base:'b -> 'a list -> 'b",
      "val mapi_with : base:Z.t -> ( Z.t -> 'a -> 'b ) -> 'a list -> 'b list",
      "val mapi : ( Z.t -> 'a -> 'b ) -> 'a list -> 'b list",
      "val filter : ( 'a -> bool ) -> 'a list -> 'a list",
      "val filter_map : ( 'a -> 'b option ) -> 'a list -> 'b list",
      "val flat_map : ( 'a -> 'b list ) -> 'a list -> 'b list",
      "val find : ( 'a -> bool ) -> 'a list -> 'a option",
      "val mem : 'a -> 'a list -> bool",
      "val mem_assoc : 'a -> ('a * 'b) list -> bool",
      "val nth : Z.t -> 'a list -> 'a option",
      "val assoc : 'a -> ('a * 'b) list -> 'b option",
      "val take : int -> 'a list -> 'a list",
      "val drop : int -> 'a list -> 'a list",
      "val (--) : int -> int -> int list",
      "val insert_sorted : leq:( 'a -> 'a -> bool ) -> 'a -> 'a list -> 'a list",
      "val sort : leq:( 'a -> 'a -> bool ) -> 'a list -> 'a list",
      "val is_sorted : leq:( 'a -> 'a -> bool ) -> 'a list -> bool",
      "val monoid_product : 'a list -> 'b list -> ('a * 'b) list",
      "val (>|=) : 'a list -> ( 'a -> 'b ) -> 'b list",
      "val (>>=) : 'a list -> ( 'a -> 'b list ) -> 'b list",
      "val let+ : 'a list -> ( 'a -> 'b ) -> 'b list",
      "val and+ : 'a list -> 'b list -> ('a * 'b) list",
      "val let* : 'a list -> ( 'a -> 'b list ) -> 'b list",
      "val and* : 'a list -> 'b list -> ('a * 'b) list"
    ]
  }
}
