---
tags:
  - List
---

# List

A list is a data type which can hold several instances of a singular type. Consider the below definition of creating a List of ByStr20.

```ocaml
field state_list_users : List ByStr20 = Nil {ByStr20} (* an empty List of ByStr20's*)

transition Test()
  current_list <- state_list_users; (* read the list *)
  new_user = Cons {ByStr20} _sender current_list; (* Create a new list element and append to the current list *)
  state_list_users := new_user (* set the appended list into state *)
end
```

## Example list contract

```ocaml
scilla_version 0
(***************************************************)
(* List operations                                 *)
(***************************************************)
import ListUtils BoolUtils

library List

let empty_list = Nil {Uint32}

let one   = Uint32 1 (* numbers 1, 2, 3 and 4 to use below *)
let two   = Uint32 2
let three = Uint32 3
let four = Uint32 4

let create_3el_list = (* utility to create a list with 3 elements *)
  fun (e1 : Uint32) =>
  fun (e2 : Uint32) =>
  fun (e3 : Uint32) =>
  let nil = empty_list in
      let le3 = Cons {Uint32} e3 empty_list in (* insert in front *)
      let le2e3 = Cons {Uint32} e2 le3 in
      Cons {Uint32} e1 le2e3 (* [e1, e2, e3] *)

let equal = fun (a: Uint32) => fun(b: Uint32) =>
  builtin eq a b

let not_equal = fun (a: Uint32) => fun(b: Uint32) =>
  let equal = builtin eq a b in
  negb equal (* from BoolUtils *)

(* utility to remove all elements that equal a value from a lit *)
let remove_elements_from_list = fun(value: Uint32) => fun(l: List Uint32) =>
  let f = not_equal value in
  let filterUint32 = @list_filter Uint32 in (* from ListUtils *)
  filterUint32 f l

(* check if two list l1 and l2 have no common elements:         *)
(* for each element in the first list, we check if it exists    *)
(* in the second list. If any such element exists, we return    *)
(* False (not disjunct) otherwise we return True                *)

(* return true if l[i] != value for all elements l[i] in the list l *)
let all_elements_different_from_value =
  fun(l: List Uint32) =>
  fun(value: Uint32) =>
    let f = not_equal value in
    let for_allUint32 = @list_forall Uint32 in (* from ListUtiles *)
    for_allUint32 f l (* checks if all elements are NOT equal to value *)

(* return true if no element in l1 is also in l2, or, put differently,  *)
(* check for each element in l1 if all elements in l2 are different     *)
let are_lists_disjunct =
  fun(l1: List Uint32) =>
  fun(l2: List Uint32) =>
    let f = all_elements_different_from_value l2 in (* apply above expression to l2 *)
    let for_allUint32 = @list_forall Uint32 in
    for_allUint32 f l1 (* apply now this f to l1 *)


(* count the number of occurences of a value in a list *)
let count_in_list =
  fun(l: List Uint32) =>
  fun(value: Uint32) =>
    let f = (* increase accumulator if element equals value *)
      fun(acc: Uint32) => fun(element: Uint32) =>
      let equal = builtin eq value element in
      match equal with
      | False => acc
      | True => builtin add acc one
      end in
    let init = Uint32 0 in (* initial value of accumulator *)
    let folder = @list_foldl Uint32 Uint32 in
    folder f init l

(* check if all elements in a list are unique                               *)
(* we apply above counter to each element and check if it is exactly 1      *)
(* if it is bigger than 1 for an element we are done and the result is fale *)
let is_unique =
  fun(l: List Uint32) =>
    let f = fun(value: Uint32) =>
      let num = count_in_list l value in
      builtin eq num one in
    let for_allUint32 = @list_forall Uint32 in
    for_allUint32 f l (* apply now this f to l1 *)


contract List()

field list : List Uint32 = empty_list
field doubles : Map Uint32 Uint32 = Emp Uint32 Uint32 (* doubles[l[i]]=2*l[i] *)

(* create lists [1,2,3] or [1,2,1] and store in field list *)
transition Create123()
  l = create_3el_list one two three; (* [1, 2, 3] *)
  list := l
end

transition Create121()
  l = create_3el_list one two one; (* [1, 2, 1] *)
  list := l
end

(* access n-th element of a list using list_nth, and emit it *)
transition ElementAtPosition(n: Uint32)
  l <- list;
  el_opt =
    let nth = @list_nth Uint32 in (* from ListUtils *)
    nth n l; (* note that indexing starts at 0 *)
  match el_opt with (* Option is None if no element with index i in list *)
  | None => (* index is out of bounds: no such element *)
    ev = {_eventname: "ElementAtPositionFailure"};
    event ev
  | Some el => (* list[i] = el *)
    ev = {_eventname: "ElementAtPositionSuccess"; index: n; element: el};
    event ev
  end
end

(* remove elements from list that equal to value *)
transition RemoveIfEqualtTo(value: Uint32)
  l <- list;
  list_without_values = remove_elements_from_list value l;
  list := list_without_values
end

(* compare the lists [1,2,3] and [3 2 1] *)
transition Compare123To321()
  l123 = create_3el_list one two three; (* [1, 2, 3] *)
  l321 = create_3el_list three two one; (* [3, 2, 1] *)
  list_zip_eq_with = @list_zip_with Uint32 Uint32 Bool; (* from ListUtils *)
  r = list_zip_eq_with equal l123 l321;
  ev = {_eventname : "Compare123To321"; result: r};
  event ev
end

(* compute the element wise difference of 2 lists *)
transition Difference321Minus111()
    l321 = create_3el_list three two one; (* [3, 2, 1] *)
    l111 = create_3el_list one one one; (* [1, 1, 1] *)
    list_zip_diff = @list_zip_with Uint32 Uint32 Uint32; (* from ListUtils *)
    r = let diff = fun (a: Uint32) => fun(b: Uint32) => builtin sub a b in (* diff = a - b *)
      list_zip_diff diff l321 l111;
    ev = {_eventname: "Difference321Minus111"; result: r};
    event ev
end

(* compute 2*l[i] and store in doubles[l[i]] *)
procedure Twice(v: Uint32)
  res =
    let two = Uint32 2 in (* res = 2 * v *)
    builtin mul v two;
  doubles[v] := res (* store in map *)
end
transition ComputeDoubles()
  l <- list;
  forall l Twice (* apply Twice(.) to each element *)
end

(* sum the elements of a list using a left fold: res = 1 + 1 + 2 = 4 *)
transition SumElements112()
  l = create_3el_list one one two; (* [1, 1, 2] *)
  folder = @list_foldl Uint32 Uint32; (* accumulator and list elements are of type Uint32 *)
  sum_of_elements =
    let init = Uint32 0 in (* initialize the accumulator at 0 *)
    let addition = (* add elements to accumulator: a + b *)
      fun(a: Uint32) => fun(b: Uint32) =>
        builtin add a b in
    folder addition init l;
  ev = {_eventname: "SumElements112"; sum: sum_of_elements};
  event ev
end

(* check if two lists l1 and l2 have at least one common element  *)
(* if they have, they are not disjunct                            *)
transition AreListsDisjunct()
  (* create a few lists for testing *)
  l1 = Cons {Uint32} one empty_list;      (* [1] *)
  l2 = Cons {Uint32} two empty_list;      (* [2] *)
  l32 = Cons {Uint32} three l2;           (* [3,2] *)
  l41 = Cons {Uint32} four l1;            (* [4,1] *)
  l111 = create_3el_list one one one;     (* [1,1,1] *)
  l131 = create_3el_list one three one;   (* [1,3,1] *)
  l243 = create_3el_list two four three;  (* [2,4,3] *)
  (* apply are_lists_disjunct to some pair of the lists *)
  check_1_2       = are_lists_disjunct l1 l2;         (* True *)
  check_1_32      = are_lists_disjunct l1 l32;       (* True *)
  check_2_32      = are_lists_disjunct l2 l32;       (* False *)
  check_32_41     = are_lists_disjunct l32 l41;     (* True *)
  check_1_111     = are_lists_disjunct l1 l111;     (* False *)
  check_111_2     = are_lists_disjunct l111 l2;     (* True *)
  check_32_111    = are_lists_disjunct l32 l111;   (* True *)
  check_111_131   = are_lists_disjunct l111 l131; (* False *)
  check_111_243   = are_lists_disjunct l111 l243; (* True *)
  (* emit results *)
  ev = {_eventname: "AreListsDisjunct";
        check_1_2: check_1_2;
        check_1_32: check_1_32;
        check_2_32: check_2_32;
        check_32_41: check_32_41;
        check_1_111: check_1_111;
        check_111_2: check_111_2;
        check_32_111: check_32_111;
        check_111_131: check_111_131;
        check_111_243: check_111_243
  };
  event ev
end

(* count the number of occurences of a value in a list *)
transition Count()
  (* create a few lists for testing *)
  l111 = create_3el_list one one one;     (* [1,1,1] *)
  l131 = create_3el_list one three one;   (* [1,3,1] *)
  l243 = create_3el_list two four three;  (* [2,4,3] *)
  (* apply count_in_list to some value and the test lists *)
  check_1_in_empty= count_in_list empty_list one; (* 0 *)
  check_1_in_243  = count_in_list l243 one; (* 0 *)
  check_1_in_131  = count_in_list l131 one; (* 2 *)
  check_1_in_111  = count_in_list l111 one; (* 3 *)
  (* emit results *)
  ev = {_eventname: "Count";
        check_1_in_empty: check_1_in_empty;
        check_1_in_243: check_1_in_243;
        check_1_in_131: check_1_in_131;
        check_1_in_111: check_1_in_111
  };
  event ev
end

transition CheckUniqueness()
  (* create a few lists for testing *)
  l1 = Cons {Uint32} one empty_list;      (* [1] *)
  l123 = create_3el_list one two three;   (* [1,2,3] *)
  l131 = create_3el_list one three one;   (* [1,3,1] *)
  l311 = create_3el_list three one one;   (* [3,1,1] *)
  (* apply is_uniqe to some lists *)
  chk_empty = is_unique empty_list; (* true *)
  chk_1     = is_unique l1;         (* true *)
  chk_123   = is_unique l123;       (* true *)
  chk_131   = is_unique l131;       (* false *)
  chk_311   = is_unique l311;       (* false *)
  (* emit results *)
  ev = {_eventname: "CheckUniqueness";
        chk_empty: chk_empty;
        chk_1: chk_1;
        chk_123: chk_123;
        chk_131: chk_131;
        chk_311: chk_311
  };
  event ev
end
```

## User defined list functions

The below snippets are user defined library snippets which involve the List type.

### listByStr20Contains

```ocaml
let listByStr20Contains =
  fun(list: List ByStr20) =>
  fun(bs: ByStr20) =>
    let listMemByStr20 = @list_mem ByStr20 in
      listMemByStr20 eqByStr20 bs list
```

### listByStr20Excludes

```ocaml
let listByStr20Excludes =
  fun(list: List ByStr20) =>
  fun(bs: ByStr20) =>
    let b = listByStr20Contains list bs in negb b
```

### listByStr20FilterOut

```ocaml
let listByStr20FilterOut =
  fun(list: List ByStr20) =>
  fun(bs: ByStr20) =>
    let listByStr20Filter = @list_filter ByStr20 in
    let fn = fun(v: ByStr20) =>
      let b = builtin eq v bs in
       negb b in
      listByStr20Filter fn list
```

## Further reading

[TheDrBee - List.Scilla](https://github.com/TheDrBee/oSCILLAtor/blob/24e03d7f14802f84a1db4c183031d1f916eeac88/contracts/List.scilla)
[Scilla Documentation - List](https://scilla.readthedocs.io/en/latest/scilla-in-depth.html?highlight=list#list)
