From 5b98df40e931884f044d5176fc19c1ecdfb3e47d Mon Sep 17 00:00:00 2001
From: Norbiox <norbertchmiel.it@gmail.com>
Date: Thu, 25 Jan 2024 15:17:47 +0100
Subject: [PATCH 01/24] add list-ops exercise configuration

---
 config.json                                   |   8 ++
 .../practice/list-ops/.docs/instructions.md   |  19 ++++
 exercises/practice/list-ops/.meta/config.json |  17 +++
 exercises/practice/list-ops/.meta/example.nim |   0
 exercises/practice/list-ops/.meta/tests.toml  | 106 ++++++++++++++++++
 exercises/practice/list-ops/list_ops.nim      |   0
 exercises/practice/list-ops/test_list_ops.nim |   0
 7 files changed, 150 insertions(+)
 create mode 100644 exercises/practice/list-ops/.docs/instructions.md
 create mode 100644 exercises/practice/list-ops/.meta/config.json
 create mode 100644 exercises/practice/list-ops/.meta/example.nim
 create mode 100644 exercises/practice/list-ops/.meta/tests.toml
 create mode 100644 exercises/practice/list-ops/list_ops.nim
 create mode 100644 exercises/practice/list-ops/test_list_ops.nim

diff --git a/config.json b/config.json
index 32448b50..381d84fd 100644
--- a/config.json
+++ b/config.json
@@ -979,6 +979,14 @@
           "events",
           "reactive_programming"
         ]
+      },
+      {
+        "slug": "list-ops",
+        "name": "List Ops",
+        "uuid": "779343ba-9b40-4d43-b696-2267c4eecde0",
+        "practices": [],
+        "prerequisites": [],
+        "difficulty": 1
       }
     ]
   },
diff --git a/exercises/practice/list-ops/.docs/instructions.md b/exercises/practice/list-ops/.docs/instructions.md
new file mode 100644
index 00000000..ebc5dffe
--- /dev/null
+++ b/exercises/practice/list-ops/.docs/instructions.md
@@ -0,0 +1,19 @@
+# Instructions
+
+Implement basic list operations.
+
+In functional languages list operations like `length`, `map`, and `reduce` are very common.
+Implement a series of basic list operations, without using existing functions.
+
+The precise number and names of the operations to be implemented will be track dependent to avoid conflicts with existing names, but the general operations you will implement include:
+
+- `append` (_given two lists, add all items in the second list to the end of the first list_);
+- `concatenate` (_given a series of lists, combine all items in all lists into one flattened list_);
+- `filter` (_given a predicate and a list, return the list of all items for which `predicate(item)` is True_);
+- `length` (_given a list, return the total number of items within it_);
+- `map` (_given a function and a list, return the list of the results of applying `function(item)` on all items_);
+- `foldl` (_given a function, a list, and initial accumulator, fold (reduce) each item into the accumulator from the left_);
+- `foldr` (_given a function, a list, and an initial accumulator, fold (reduce) each item into the accumulator from the right_);
+- `reverse` (_given a list, return a list with all the original items, but in reversed order_).
+
+Note, the ordering in which arguments are passed to the fold functions (`foldl`, `foldr`) is significant.
diff --git a/exercises/practice/list-ops/.meta/config.json b/exercises/practice/list-ops/.meta/config.json
new file mode 100644
index 00000000..67415bc3
--- /dev/null
+++ b/exercises/practice/list-ops/.meta/config.json
@@ -0,0 +1,17 @@
+{
+  "authors": [
+    "Norbiox"
+  ],
+  "files": {
+    "solution": [
+      "list_ops.nim"
+    ],
+    "test": [
+      "test_list_ops.nim"
+    ],
+    "example": [
+      ".meta/example.nim"
+    ]
+  },
+  "blurb": "Implement basic list operations."
+}
diff --git a/exercises/practice/list-ops/.meta/example.nim b/exercises/practice/list-ops/.meta/example.nim
new file mode 100644
index 00000000..e69de29b
diff --git a/exercises/practice/list-ops/.meta/tests.toml b/exercises/practice/list-ops/.meta/tests.toml
new file mode 100644
index 00000000..08b1edc0
--- /dev/null
+++ b/exercises/practice/list-ops/.meta/tests.toml
@@ -0,0 +1,106 @@
+# This is an auto-generated file.
+#
+# Regenerating this file via `configlet sync` will:
+# - Recreate every `description` key/value pair
+# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications
+# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion)
+# - Preserve any other key/value pair
+#
+# As user-added comments (using the # character) will be removed when this file
+# is regenerated, comments can be added via a `comment` key.
+
+[485b9452-bf94-40f7-a3db-c3cf4850066a]
+description = "append entries to a list and return the new list -> empty lists"
+
+[2c894696-b609-4569-b149-8672134d340a]
+description = "append entries to a list and return the new list -> list to empty list"
+
+[e842efed-3bf6-4295-b371-4d67a4fdf19c]
+description = "append entries to a list and return the new list -> empty list to list"
+
+[71dcf5eb-73ae-4a0e-b744-a52ee387922f]
+description = "append entries to a list and return the new list -> non-empty lists"
+
+[28444355-201b-4af2-a2f6-5550227bde21]
+description = "concatenate a list of lists -> empty list"
+
+[331451c1-9573-42a1-9869-2d06e3b389a9]
+description = "concatenate a list of lists -> list of lists"
+
+[d6ecd72c-197f-40c3-89a4-aa1f45827e09]
+description = "concatenate a list of lists -> list of nested lists"
+
+[0524fba8-3e0f-4531-ad2b-f7a43da86a16]
+description = "filter list returning only values that satisfy the filter function -> empty list"
+
+[88494bd5-f520-4edb-8631-88e415b62d24]
+description = "filter list returning only values that satisfy the filter function -> non-empty list"
+
+[1cf0b92d-8d96-41d5-9c21-7b3c37cb6aad]
+description = "returns the length of a list -> empty list"
+
+[d7b8d2d9-2d16-44c4-9a19-6e5f237cb71e]
+description = "returns the length of a list -> non-empty list"
+
+[c0bc8962-30e2-4bec-9ae4-668b8ecd75aa]
+description = "return a list of elements whose values equal the list value transformed by the mapping function -> empty list"
+
+[11e71a95-e78b-4909-b8e4-60cdcaec0e91]
+description = "return a list of elements whose values equal the list value transformed by the mapping function -> non-empty list"
+
+[613b20b7-1873-4070-a3a6-70ae5f50d7cc]
+description = "folds (reduces) the given list from the left with a function -> empty list"
+include = false
+
+[e56df3eb-9405-416a-b13a-aabb4c3b5194]
+description = "folds (reduces) the given list from the left with a function -> direction independent function applied to non-empty list"
+include = false
+
+[d2cf5644-aee1-4dfc-9b88-06896676fe27]
+description = "folds (reduces) the given list from the left with a function -> direction dependent function applied to non-empty list"
+include = false
+
+[36549237-f765-4a4c-bfd9-5d3a8f7b07d2]
+description = "folds (reduces) the given list from the left with a function -> empty list"
+reimplements = "613b20b7-1873-4070-a3a6-70ae5f50d7cc"
+
+[7a626a3c-03ec-42bc-9840-53f280e13067]
+description = "folds (reduces) the given list from the left with a function -> direction independent function applied to non-empty list"
+reimplements = "e56df3eb-9405-416a-b13a-aabb4c3b5194"
+
+[d7fcad99-e88e-40e1-a539-4c519681f390]
+description = "folds (reduces) the given list from the left with a function -> direction dependent function applied to non-empty list"
+reimplements = "d2cf5644-aee1-4dfc-9b88-06896676fe27"
+
+[aeb576b9-118e-4a57-a451-db49fac20fdc]
+description = "folds (reduces) the given list from the right with a function -> empty list"
+include = false
+
+[c4b64e58-313e-4c47-9c68-7764964efb8e]
+description = "folds (reduces) the given list from the right with a function -> direction independent function applied to non-empty list"
+include = false
+
+[be396a53-c074-4db3-8dd6-f7ed003cce7c]
+description = "folds (reduces) the given list from the right with a function -> direction dependent function applied to non-empty list"
+include = false
+
+[17214edb-20ba-42fc-bda8-000a5ab525b0]
+description = "folds (reduces) the given list from the right with a function -> empty list"
+reimplements = "aeb576b9-118e-4a57-a451-db49fac20fdc"
+
+[e1c64db7-9253-4a3d-a7c4-5273b9e2a1bd]
+description = "folds (reduces) the given list from the right with a function -> direction independent function applied to non-empty list"
+reimplements = "c4b64e58-313e-4c47-9c68-7764964efb8e"
+
+[8066003b-f2ff-437e-9103-66e6df474844]
+description = "folds (reduces) the given list from the right with a function -> direction dependent function applied to non-empty list"
+reimplements = "be396a53-c074-4db3-8dd6-f7ed003cce7c"
+
+[94231515-050e-4841-943d-d4488ab4ee30]
+description = "reverse the elements of the list -> empty list"
+
+[fcc03d1e-42e0-4712-b689-d54ad761f360]
+description = "reverse the elements of the list -> non-empty list"
+
+[40872990-b5b8-4cb8-9085-d91fc0d05d26]
+description = "reverse the elements of the list -> list of lists is not flattened"
diff --git a/exercises/practice/list-ops/list_ops.nim b/exercises/practice/list-ops/list_ops.nim
new file mode 100644
index 00000000..e69de29b
diff --git a/exercises/practice/list-ops/test_list_ops.nim b/exercises/practice/list-ops/test_list_ops.nim
new file mode 100644
index 00000000..e69de29b

From cf1d2ae301955e6a8aeea9c67b0b1de98850500f Mon Sep 17 00:00:00 2001
From: Norbiox <norbertchmiel.it@gmail.com>
Date: Thu, 25 Jan 2024 21:42:37 +0100
Subject: [PATCH 02/24] add tests file scaffold

---
 exercises/practice/list-ops/test_list_ops.nim | 103 ++++++++++++++++++
 1 file changed, 103 insertions(+)

diff --git a/exercises/practice/list-ops/test_list_ops.nim b/exercises/practice/list-ops/test_list_ops.nim
index e69de29b..d50838db 100644
--- a/exercises/practice/list-ops/test_list_ops.nim
+++ b/exercises/practice/list-ops/test_list_ops.nim
@@ -0,0 +1,103 @@
+import unittest
+import list_ops
+
+
+suite "append entries to a list and return the new list":
+  test "empty lists":  # 485b9452-bf94-40f7-a3db-c3cf4850066a
+    discard
+
+  test "list to empty list":  # 2c894696-b609-4569-b149-8672134d340a
+    discard
+
+  test "empty list to list":  # e842efed-3bf6-4295-b371-4d67a4fdf19c
+    discard
+
+  test "non-empty lists":  # 71dcf5eb-73ae-4a0e-b744-a52ee387922f
+    discard
+
+
+suite "concatenate a list of lists":
+  test "empty list":  # 28444355-201b-4af2-a2f6-5550227bde21
+    discard
+
+  test "list of lists":  # 331451c1-9573-42a1-9869-2d06e3b389a9
+    discard
+
+  test "list of nested lists":  # d6ecd72c-197f-40c3-89a4-aa1f45827e09
+    discard
+
+
+suite "filter list returning only values that satisfy the filter function":
+  test "empty list":  # 0524fba8-3e0f-4531-ad2b-f7a43da86a16
+    discard
+
+  test "non-empty list":  # 88494bd5-f520-4edb-8631-88e415b62d24
+    discard
+
+
+suite "returns the length of a list":
+  test "empty list":  # 1cf0b92d-8d96-41d5-9c21-7b3c37cb6aad
+    discard
+
+  test "non-empty list":  # d7b8d2d9-2d16-44c4-9a19-6e5f237cb71e
+    discard
+
+
+suite "return a list of elements whose values equal the list value transformed by the mapping function":
+  test "empty list":  # c0bc8962-30e2-4bec-9ae4-668b8ecd75aa
+    discard
+
+  test "non-empty list":  # 11e71a95-e78b-4909-b8e4-60cdcaec0e91
+    discard
+
+
+suite "folds (reduces) the given list from the left with a function":
+  test "empty list":  # 613b20b7-1873-4070-a3a6-70ae5f50d7cc
+    discard
+
+  test "direction independent function applied to non-empty list":  # e56df3eb-9405-416a-b13a-aabb4c3b5194
+    discard
+
+  test "direction dependent function applied to non-empty list":  # d2cf5644-aee1-4dfc-9b88-06896676fe27
+    discard
+
+  test "empty list":  # 36549237-f765-4a4c-bfd9-5d3a8f7b07d2
+    discard
+
+  test "direction independent function applied to non-empty list":  # 7a626a3c-03ec-42bc-9840-53f280e13067
+    discard
+
+  test "direction dependent function applied to non-empty list":  # d7fcad99-e88e-40e1-a539-4c519681f390
+    discard
+
+
+suite "folds (reduces) the given list from the right with a function":
+  test "empty list":  # aeb576b9-118e-4a57-a451-db49fac20fdc
+    discard
+
+  test "direction independent function applied to non-empty list":  # c4b64e58-313e-4c47-9c68-7764964efb8e
+    discard
+
+  test "direction dependent function applied to non-empty list":  # be396a53-c074-4db3-8dd6-f7ed003cce7c
+    discard
+
+  test "empty list":  # 17214edb-20ba-42fc-bda8-000a5ab525b0
+    discard
+
+  test "direction independent function applied to non-empty list":  # e1c64db7-9253-4a3d-a7c4-5273b9e2a1bd
+    discard
+
+  test "direction dependent function applied to non-empty list":  # 8066003b-f2ff-437e-9103-66e6df474844
+    discard
+
+
+suite "reverse the elements of the list":
+  test "empty list":  # 94231515-050e-4841-943d-d4488ab4ee30
+    discard
+
+  test "non-empty list":  # fcc03d1e-42e0-4712-b689-d54ad761f360
+    discard
+
+  test "list of lists is not flattened":  # 40872990-b5b8-4cb8-9085-d91fc0d05d26
+    discard
+

From 43ee62a1c6e653a1b9cff2ecfef31d12a888205b Mon Sep 17 00:00:00 2001
From: Norbiox <norbertchmiel.it@gmail.com>
Date: Sat, 27 Jan 2024 11:50:13 +0100
Subject: [PATCH 03/24] add tests and example solutions

---
 exercises/practice/list-ops/.meta/example.nim | 44 +++++++++++
 exercises/practice/list-ops/.meta/tests.toml  |  8 +-
 exercises/practice/list-ops/list_ops.nim      | 23 ++++++
 exercises/practice/list-ops/test_list_ops.nim | 76 +++++++++++--------
 4 files changed, 117 insertions(+), 34 deletions(-)

diff --git a/exercises/practice/list-ops/.meta/example.nim b/exercises/practice/list-ops/.meta/example.nim
index e69de29b..c817b154 100644
--- a/exercises/practice/list-ops/.meta/example.nim
+++ b/exercises/practice/list-ops/.meta/example.nim
@@ -0,0 +1,44 @@
+proc append*(list1, list2: seq[int]): seq[int] =
+  if list2.len == 0:
+    return list1
+  return append(list1 & list2[0], list2[1..^1])
+
+proc concatenate*(lists: seq[seq[int]]): seq[int] =
+  var newList = newSeq[int]()
+  for list in lists:
+    newList = append(newList, list)
+  return newList
+
+proc filter*(predicate: proc(x: int): bool, list: seq[int]): seq[int] =
+  var newList = newSeq[int]()
+  for x in list:
+    if predicate(x):
+      newList.add(x)
+  return newList
+
+proc length*(list: seq[int]): int =
+  var len = 0
+  for _ in list:
+    len += 1
+  return len
+
+proc map*(function: proc(x: int): int, list: seq[int]): seq[int] =
+  var newList = newSeq[int]()
+  for x in list:
+    newList.add(function(x))
+  return newList
+
+proc foldl*(function: proc(x, y: int): int, list: seq[int], accumulator: int): int =
+  if list.len == 0:
+    return accumulator
+  return foldl(function, list[1..^1], function(accumulator, list[0]))
+
+proc foldr*(function: proc(x, y: int): int, list: seq[int], accumulator: int): int =
+  if list.len == 0:
+    return accumulator
+  return function(foldr(function, list[1..^1], accumulator), list[0])
+
+proc reverse*(list: seq[int]): seq[int] =
+  var newList = newSeq[int]()
+  for x in list: newList.insert(x, 0)
+  return newList
diff --git a/exercises/practice/list-ops/.meta/tests.toml b/exercises/practice/list-ops/.meta/tests.toml
index 08b1edc0..16a0fca6 100644
--- a/exercises/practice/list-ops/.meta/tests.toml
+++ b/exercises/practice/list-ops/.meta/tests.toml
@@ -27,8 +27,8 @@ description = "concatenate a list of lists -> empty list"
 [331451c1-9573-42a1-9869-2d06e3b389a9]
 description = "concatenate a list of lists -> list of lists"
 
-[d6ecd72c-197f-40c3-89a4-aa1f45827e09]
-description = "concatenate a list of lists -> list of nested lists"
+# [d6ecd72c-197f-40c3-89a4-aa1f45827e09]
+# description = "concatenate a list of lists -> list of nested lists"
 
 [0524fba8-3e0f-4531-ad2b-f7a43da86a16]
 description = "filter list returning only values that satisfy the filter function -> empty list"
@@ -102,5 +102,5 @@ description = "reverse the elements of the list -> empty list"
 [fcc03d1e-42e0-4712-b689-d54ad761f360]
 description = "reverse the elements of the list -> non-empty list"
 
-[40872990-b5b8-4cb8-9085-d91fc0d05d26]
-description = "reverse the elements of the list -> list of lists is not flattened"
+# [40872990-b5b8-4cb8-9085-d91fc0d05d26]
+# description = "reverse the elements of the list -> list of lists is not flattened"
diff --git a/exercises/practice/list-ops/list_ops.nim b/exercises/practice/list-ops/list_ops.nim
index e69de29b..34c75a86 100644
--- a/exercises/practice/list-ops/list_ops.nim
+++ b/exercises/practice/list-ops/list_ops.nim
@@ -0,0 +1,23 @@
+proc append*(list1, list2: seq[int]): seq[int] =
+  discard
+
+proc concatenate*(lists: seq[seq[int]]): seq[int] =
+  discard
+
+proc filter*(predicate: proc(x: int): bool, list: seq[int]): seq[int] =
+  discard
+
+proc length*(list: seq[int]): int =
+  discard
+
+proc map*(function: proc(x: int): int, list: seq[int]): seq[int] =
+  discard
+
+proc foldl*(function: proc(x, y: int): int, list: seq[int], accumulator: int): int =
+  discard
+
+proc foldr*(function: proc(x, y: int): int, list: seq[int], accumulator: int): int =
+  discard
+
+proc reverse*(list: seq[int]): seq[int] =
+  discard
diff --git a/exercises/practice/list-ops/test_list_ops.nim b/exercises/practice/list-ops/test_list_ops.nim
index d50838db..9a4416f9 100644
--- a/exercises/practice/list-ops/test_list_ops.nim
+++ b/exercises/practice/list-ops/test_list_ops.nim
@@ -4,100 +4,116 @@ import list_ops
 
 suite "append entries to a list and return the new list":
   test "empty lists":  # 485b9452-bf94-40f7-a3db-c3cf4850066a
-    discard
+    check append(@[], @[]) == newSeq[int]()
 
   test "list to empty list":  # 2c894696-b609-4569-b149-8672134d340a
-    discard
+    check append(@[], @[1, 2, 3, 4]) == @[1, 2, 3, 4]
 
   test "empty list to list":  # e842efed-3bf6-4295-b371-4d67a4fdf19c
-    discard
+    check append(@[1, 2, 3, 4], @[]) == @[1, 2, 3, 4]
 
   test "non-empty lists":  # 71dcf5eb-73ae-4a0e-b744-a52ee387922f
-    discard
+    check append(@[1, 2], @[2, 3, 4, 5]) == @[1, 2, 2, 3, 4, 5]
 
 
 suite "concatenate a list of lists":
   test "empty list":  # 28444355-201b-4af2-a2f6-5550227bde21
-    discard
+    check concatenate(@[]) == newSeq[int]()
 
   test "list of lists":  # 331451c1-9573-42a1-9869-2d06e3b389a9
-    discard
+    check concatenate(@[@[1, 2], @[3], @[], @[4, 5, 6]]) == @[1, 2, 3, 4, 5, 6]
 
-  test "list of nested lists":  # d6ecd72c-197f-40c3-89a4-aa1f45827e09
-    discard
+  # test "list of nested lists":  # d6ecd72c-197f-40c3-89a4-aa1f45827e09
+  #   check concatenate(@[@[@[1], @[2]], @[@[3]], @[@[]], @[@[4, 5, 6]]]) == @[@[1], @[2], @[3], @[], @[4, 5, 6]]
 
 
 suite "filter list returning only values that satisfy the filter function":
+  func predicate(x: int): bool = x mod 2 == 1
+
   test "empty list":  # 0524fba8-3e0f-4531-ad2b-f7a43da86a16
-    discard
+    check filter(predicate, @[]) == newSeq[int]()
 
   test "non-empty list":  # 88494bd5-f520-4edb-8631-88e415b62d24
-    discard
+    check filter(predicate, @[1, 2, 3, 5]) == @[1, 3, 5]
 
 
 suite "returns the length of a list":
   test "empty list":  # 1cf0b92d-8d96-41d5-9c21-7b3c37cb6aad
-    discard
+    check length(@[]) == 0
 
   test "non-empty list":  # d7b8d2d9-2d16-44c4-9a19-6e5f237cb71e
-    discard
+    check length(@[1, 2, 3, 4]) == 4
 
 
 suite "return a list of elements whose values equal the list value transformed by the mapping function":
+  func function(x: int): int = x + 1
+
   test "empty list":  # c0bc8962-30e2-4bec-9ae4-668b8ecd75aa
-    discard
+    check map(function, @[]) == newSeq[int]()
 
   test "non-empty list":  # 11e71a95-e78b-4909-b8e4-60cdcaec0e91
-    discard
+    check map(function, @[1, 3, 5, 7]) == @[2, 4, 6, 8]
 
 
 suite "folds (reduces) the given list from the left with a function":
   test "empty list":  # 613b20b7-1873-4070-a3a6-70ae5f50d7cc
-    discard
+    func function(x: int, y: int): int = x + y
+    check foldl(function, @[], 2) == 2
 
   test "direction independent function applied to non-empty list":  # e56df3eb-9405-416a-b13a-aabb4c3b5194
-    discard
+    func function(x: int, y: int): int = x + y
+    check foldl(function, @[1, 2, 3, 4], 5) == 15
 
   test "direction dependent function applied to non-empty list":  # d2cf5644-aee1-4dfc-9b88-06896676fe27
-    discard
+    func function(x: int, y: int): int | float = x - y
+    check foldl(function, @[1, 2, 3, 4], 24) == 14
 
   test "empty list":  # 36549237-f765-4a4c-bfd9-5d3a8f7b07d2
-    discard
+    func function(x: int, y: int): int = y + x
+    check foldl(function, @[], 2) == 2
 
   test "direction independent function applied to non-empty list":  # 7a626a3c-03ec-42bc-9840-53f280e13067
-    discard
+    func function(x: int, y: int): int = y + x
+    check foldl(function, @[1, 2, 3, 4], 5) == 15
 
   test "direction dependent function applied to non-empty list":  # d7fcad99-e88e-40e1-a539-4c519681f390
-    discard
+    func function(x: int, y: int): int = y - x
+    check foldl(function, @[1, 2, 3, 4], 5) == 7
 
 
 suite "folds (reduces) the given list from the right with a function":
   test "empty list":  # aeb576b9-118e-4a57-a451-db49fac20fdc
-    discard
+    func function(x: int, y: int): int = x + y
+    check foldr(function, @[], 2) == 2
 
   test "direction independent function applied to non-empty list":  # c4b64e58-313e-4c47-9c68-7764964efb8e
-    discard
+    func function(x: int, y: int): int = x + y
+    check foldr(function, @[1, 2, 3, 4], 5) == 15
 
   test "direction dependent function applied to non-empty list":  # be396a53-c074-4db3-8dd6-f7ed003cce7c
-    discard
+    func function(x: int, y: int): int | float = x - y
+    check foldr(function, @[1, 2, 3, 4], 24) == 14
 
   test "empty list":  # 17214edb-20ba-42fc-bda8-000a5ab525b0
-    discard
+    func function(x: int, y: int): int = y + x
+    check foldr(function, @[], 2) == 2
 
   test "direction independent function applied to non-empty list":  # e1c64db7-9253-4a3d-a7c4-5273b9e2a1bd
-    discard
+    func function(x: int, y: int): int = y + x
+    check foldr(function, @[1, 2, 3, 4], 5) == 15
 
   test "direction dependent function applied to non-empty list":  # 8066003b-f2ff-437e-9103-66e6df474844
-    discard
+    func function(x: int, y: int): int = y - x
+    check foldr(function, @[1, 2, 3, 4], 5) == 3
 
 
 suite "reverse the elements of the list":
   test "empty list":  # 94231515-050e-4841-943d-d4488ab4ee30
-    discard
+    check reverse(@[]) == newSeq[int]()
 
   test "non-empty list":  # fcc03d1e-42e0-4712-b689-d54ad761f360
-    discard
+    check reverse(@[1, 2, 3, 4]) == @[4, 3, 2, 1]
 
-  test "list of lists is not flattened":  # 40872990-b5b8-4cb8-9085-d91fc0d05d26
-    discard
+  # test "list of lists is not flattened":  # 40872990-b5b8-4cb8-9085-d91fc0d05d26
+    # check reverse(@[@[], @[1], @[2, 3]]) == @[@[2, 3], @[1], @[]]
 

From 8fbe2938e0a46055f23971d9d557b89fd3ba529c Mon Sep 17 00:00:00 2001
From: Norbiox <norbertchmiel.it@gmail.com>
Date: Sat, 27 Jan 2024 11:52:00 +0100
Subject: [PATCH 04/24] change difficulty and move higher in config

---
 config.json | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/config.json b/config.json
index 381d84fd..0447fdab 100644
--- a/config.json
+++ b/config.json
@@ -953,6 +953,14 @@
           "integers"
         ]
       },
+      {
+        "slug": "list-ops",
+        "name": "List Ops",
+        "uuid": "779343ba-9b40-4d43-b696-2267c4eecde0",
+        "practices": [],
+        "prerequisites": [],
+        "difficulty": 3
+      },
       {
         "slug": "linked-list",
         "name": "Linked List",
@@ -979,14 +987,6 @@
           "events",
           "reactive_programming"
         ]
-      },
-      {
-        "slug": "list-ops",
-        "name": "List Ops",
-        "uuid": "779343ba-9b40-4d43-b696-2267c4eecde0",
-        "practices": [],
-        "prerequisites": [],
-        "difficulty": 1
       }
     ]
   },

From ddc71e69b778bcd8dfbb4990c1c2eebd3cf94011 Mon Sep 17 00:00:00 2001
From: Norbiox <norbertchmiel.it@gmail.com>
Date: Sat, 27 Jan 2024 12:15:18 +0100
Subject: [PATCH 05/24] remove trailing newlines

---
 exercises/practice/list-ops/test_list_ops.nim | 1 -
 1 file changed, 1 deletion(-)

diff --git a/exercises/practice/list-ops/test_list_ops.nim b/exercises/practice/list-ops/test_list_ops.nim
index 9a4416f9..8a5fa46a 100644
--- a/exercises/practice/list-ops/test_list_ops.nim
+++ b/exercises/practice/list-ops/test_list_ops.nim
@@ -116,4 +116,3 @@ suite "reverse the elements of the list":
 
   # test "list of lists is not flattened":  # 40872990-b5b8-4cb8-9085-d91fc0d05d26
     # check reverse(@[@[], @[1], @[2, 3]]) == @[@[2, 3], @[1], @[]]
-

From 31a2f5c572cd0cc9c9f4f414172d8d8511ee9473 Mon Sep 17 00:00:00 2001
From: ee7 <45465154+ee7@users.noreply.github.com>
Date: Sat, 27 Jan 2024 14:25:01 +0100
Subject: [PATCH 06/24] exercises(list-ops): example: refactor `length`

---
 exercises/practice/list-ops/.meta/example.nim | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/exercises/practice/list-ops/.meta/example.nim b/exercises/practice/list-ops/.meta/example.nim
index c817b154..77293c5e 100644
--- a/exercises/practice/list-ops/.meta/example.nim
+++ b/exercises/practice/list-ops/.meta/example.nim
@@ -17,10 +17,9 @@ proc filter*(predicate: proc(x: int): bool, list: seq[int]): seq[int] =
   return newList
 
 proc length*(list: seq[int]): int =
-  var len = 0
+  result = 0
   for _ in list:
-    len += 1
-  return len
+    inc result
 
 proc map*(function: proc(x: int): int, list: seq[int]): seq[int] =
   var newList = newSeq[int]()

From 03e10f36644f98ce7e506488c1c629669725975c Mon Sep 17 00:00:00 2001
From: ee7 <45465154+ee7@users.noreply.github.com>
Date: Sat, 27 Jan 2024 14:25:02 +0100
Subject: [PATCH 07/24] exercises(list-ops): example: refactor `length` further

The `append`, `foldl`, and `foldr` procs each use `len`, so there's no
real benefit to pretending it doesn't exist in the `length` proc.

An alternative would be for this exercise to use some `distinct seq`,
but that's probably not worthwhile.
---
 exercises/practice/list-ops/.meta/example.nim | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/exercises/practice/list-ops/.meta/example.nim b/exercises/practice/list-ops/.meta/example.nim
index 77293c5e..a919fd02 100644
--- a/exercises/practice/list-ops/.meta/example.nim
+++ b/exercises/practice/list-ops/.meta/example.nim
@@ -17,9 +17,7 @@ proc filter*(predicate: proc(x: int): bool, list: seq[int]): seq[int] =
   return newList
 
 proc length*(list: seq[int]): int =
-  result = 0
-  for _ in list:
-    inc result
+  list.len
 
 proc map*(function: proc(x: int): int, list: seq[int]): seq[int] =
   var newList = newSeq[int]()

From 26b4b6ed973439468b299f4b71b39d44a6fbf121 Mon Sep 17 00:00:00 2001
From: ee7 <45465154+ee7@users.noreply.github.com>
Date: Sat, 27 Jan 2024 14:25:03 +0100
Subject: [PATCH 08/24] exercises(list-ops): example: use result, not newList

---
 exercises/practice/list-ops/.meta/example.nim | 20 ++++++++-----------
 1 file changed, 8 insertions(+), 12 deletions(-)

diff --git a/exercises/practice/list-ops/.meta/example.nim b/exercises/practice/list-ops/.meta/example.nim
index a919fd02..c06e3ccc 100644
--- a/exercises/practice/list-ops/.meta/example.nim
+++ b/exercises/practice/list-ops/.meta/example.nim
@@ -4,26 +4,23 @@ proc append*(list1, list2: seq[int]): seq[int] =
   return append(list1 & list2[0], list2[1..^1])
 
 proc concatenate*(lists: seq[seq[int]]): seq[int] =
-  var newList = newSeq[int]()
+  result = @[]
   for list in lists:
-    newList = append(newList, list)
-  return newList
+    result = append(result, list)
 
 proc filter*(predicate: proc(x: int): bool, list: seq[int]): seq[int] =
-  var newList = newSeq[int]()
+  result = @[]
   for x in list:
     if predicate(x):
-      newList.add(x)
-  return newList
+      result.add(x)
 
 proc length*(list: seq[int]): int =
   list.len
 
 proc map*(function: proc(x: int): int, list: seq[int]): seq[int] =
-  var newList = newSeq[int]()
+  result = @[]
   for x in list:
-    newList.add(function(x))
-  return newList
+    result.add(function(x))
 
 proc foldl*(function: proc(x, y: int): int, list: seq[int], accumulator: int): int =
   if list.len == 0:
@@ -36,6 +33,5 @@ proc foldr*(function: proc(x, y: int): int, list: seq[int], accumulator: int): i
   return function(foldr(function, list[1..^1], accumulator), list[0])
 
 proc reverse*(list: seq[int]): seq[int] =
-  var newList = newSeq[int]()
-  for x in list: newList.insert(x, 0)
-  return newList
+  result = @[]
+  for x in list: result.insert(x, 0)

From c5ffbc367c935884834a08e61772669625aaf631 Mon Sep 17 00:00:00 2001
From: ee7 <45465154+ee7@users.noreply.github.com>
Date: Sat, 27 Jan 2024 14:25:04 +0100
Subject: [PATCH 09/24] exercises(list-ops): example: format loop consistently

---
 exercises/practice/list-ops/.meta/example.nim | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/exercises/practice/list-ops/.meta/example.nim b/exercises/practice/list-ops/.meta/example.nim
index c06e3ccc..f84d53fd 100644
--- a/exercises/practice/list-ops/.meta/example.nim
+++ b/exercises/practice/list-ops/.meta/example.nim
@@ -34,4 +34,5 @@ proc foldr*(function: proc(x, y: int): int, list: seq[int], accumulator: int): i
 
 proc reverse*(list: seq[int]): seq[int] =
   result = @[]
-  for x in list: result.insert(x, 0)
+  for x in list:
+    result.insert(x, 0)

From aa462b618b3255ea378b6274a0ea373808e239c4 Mon Sep 17 00:00:00 2001
From: ee7 <45465154+ee7@users.noreply.github.com>
Date: Sat, 27 Jan 2024 14:25:05 +0100
Subject: [PATCH 10/24] exercises(list-ops): example: refactor `reverse`

---
 exercises/practice/list-ops/.meta/example.nim | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/exercises/practice/list-ops/.meta/example.nim b/exercises/practice/list-ops/.meta/example.nim
index f84d53fd..bc66cb8d 100644
--- a/exercises/practice/list-ops/.meta/example.nim
+++ b/exercises/practice/list-ops/.meta/example.nim
@@ -33,6 +33,6 @@ proc foldr*(function: proc(x, y: int): int, list: seq[int], accumulator: int): i
   return function(foldr(function, list[1..^1], accumulator), list[0])
 
 proc reverse*(list: seq[int]): seq[int] =
-  result = @[]
-  for x in list:
-    result.insert(x, 0)
+  result = newSeq[int](list.len)
+  for i, x in list:
+    result[list.high - i] = x

From 4a3cd6c997d5f4050817b8ee5c5b48ff6a03d73a Mon Sep 17 00:00:00 2001
From: ee7 <45465154+ee7@users.noreply.github.com>
Date: Sat, 27 Jan 2024 14:25:06 +0100
Subject: [PATCH 11/24] exercises(list-ops): example: remove parens for `add`

---
 exercises/practice/list-ops/.meta/example.nim | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/exercises/practice/list-ops/.meta/example.nim b/exercises/practice/list-ops/.meta/example.nim
index bc66cb8d..c6e91a0d 100644
--- a/exercises/practice/list-ops/.meta/example.nim
+++ b/exercises/practice/list-ops/.meta/example.nim
@@ -12,7 +12,7 @@ proc filter*(predicate: proc(x: int): bool, list: seq[int]): seq[int] =
   result = @[]
   for x in list:
     if predicate(x):
-      result.add(x)
+      result.add x
 
 proc length*(list: seq[int]): int =
   list.len
@@ -20,7 +20,7 @@ proc length*(list: seq[int]): int =
 proc map*(function: proc(x: int): int, list: seq[int]): seq[int] =
   result = @[]
   for x in list:
-    result.add(function(x))
+    result.add function(x)
 
 proc foldl*(function: proc(x, y: int): int, list: seq[int], accumulator: int): int =
   if list.len == 0:

From 7c3c54f6c20f8b3dbdf4bc819c7c348bf8d61c0e Mon Sep 17 00:00:00 2001
From: ee7 <45465154+ee7@users.noreply.github.com>
Date: Sat, 27 Jan 2024 14:25:07 +0100
Subject: [PATCH 12/24] exercises(list-ops): example: refactor `map`

---
 exercises/practice/list-ops/.meta/example.nim | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/exercises/practice/list-ops/.meta/example.nim b/exercises/practice/list-ops/.meta/example.nim
index c6e91a0d..e09c8282 100644
--- a/exercises/practice/list-ops/.meta/example.nim
+++ b/exercises/practice/list-ops/.meta/example.nim
@@ -18,9 +18,9 @@ proc length*(list: seq[int]): int =
   list.len
 
 proc map*(function: proc(x: int): int, list: seq[int]): seq[int] =
-  result = @[]
-  for x in list:
-    result.add function(x)
+  result = newSeq[int](list.len)
+  for i, x in list:
+    result[i] = function(x)
 
 proc foldl*(function: proc(x, y: int): int, list: seq[int], accumulator: int): int =
   if list.len == 0:

From d43eea4d53132a3c22b19a6cf47f947616f27237 Mon Sep 17 00:00:00 2001
From: ee7 <45465154+ee7@users.noreply.github.com>
Date: Sat, 27 Jan 2024 14:25:08 +0100
Subject: [PATCH 13/24] exercises(list-ops): example: avoid `return`

---
 exercises/practice/list-ops/.meta/example.nim | 15 +++++++++------
 1 file changed, 9 insertions(+), 6 deletions(-)

diff --git a/exercises/practice/list-ops/.meta/example.nim b/exercises/practice/list-ops/.meta/example.nim
index e09c8282..e2267050 100644
--- a/exercises/practice/list-ops/.meta/example.nim
+++ b/exercises/practice/list-ops/.meta/example.nim
@@ -1,7 +1,8 @@
 proc append*(list1, list2: seq[int]): seq[int] =
   if list2.len == 0:
-    return list1
-  return append(list1 & list2[0], list2[1..^1])
+    list1
+  else:
+    append(list1 & list2[0], list2[1..^1])
 
 proc concatenate*(lists: seq[seq[int]]): seq[int] =
   result = @[]
@@ -24,13 +25,15 @@ proc map*(function: proc(x: int): int, list: seq[int]): seq[int] =
 
 proc foldl*(function: proc(x, y: int): int, list: seq[int], accumulator: int): int =
   if list.len == 0:
-    return accumulator
-  return foldl(function, list[1..^1], function(accumulator, list[0]))
+    accumulator
+  else:
+    foldl(function, list[1..^1], function(accumulator, list[0]))
 
 proc foldr*(function: proc(x, y: int): int, list: seq[int], accumulator: int): int =
   if list.len == 0:
-    return accumulator
-  return function(foldr(function, list[1..^1], accumulator), list[0])
+    accumulator
+  else:
+    function(foldr(function, list[1..^1], accumulator), list[0])
 
 proc reverse*(list: seq[int]): seq[int] =
   result = newSeq[int](list.len)

From eedf26cecac8050618046d0ea9f1d306eaab7b6a Mon Sep 17 00:00:00 2001
From: ee7 <45465154+ee7@users.noreply.github.com>
Date: Sat, 27 Jan 2024 14:25:09 +0100
Subject: [PATCH 14/24] exercises(list-ops): example: use `func`

---
 exercises/practice/list-ops/.meta/example.nim | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/exercises/practice/list-ops/.meta/example.nim b/exercises/practice/list-ops/.meta/example.nim
index e2267050..c3e33fd5 100644
--- a/exercises/practice/list-ops/.meta/example.nim
+++ b/exercises/practice/list-ops/.meta/example.nim
@@ -1,41 +1,41 @@
-proc append*(list1, list2: seq[int]): seq[int] =
+func append*(list1, list2: seq[int]): seq[int] =
   if list2.len == 0:
     list1
   else:
     append(list1 & list2[0], list2[1..^1])
 
-proc concatenate*(lists: seq[seq[int]]): seq[int] =
+func concatenate*(lists: seq[seq[int]]): seq[int] =
   result = @[]
   for list in lists:
     result = append(result, list)
 
-proc filter*(predicate: proc(x: int): bool, list: seq[int]): seq[int] =
+func filter*(predicate: proc(x: int): bool {.noSideEffect.}, list: seq[int]): seq[int] =
   result = @[]
   for x in list:
     if predicate(x):
       result.add x
 
-proc length*(list: seq[int]): int =
+func length*(list: seq[int]): int =
   list.len
 
-proc map*(function: proc(x: int): int, list: seq[int]): seq[int] =
+func map*(function: proc(x: int): int {.noSideEffect.}, list: seq[int]): seq[int] =
   result = newSeq[int](list.len)
   for i, x in list:
     result[i] = function(x)
 
-proc foldl*(function: proc(x, y: int): int, list: seq[int], accumulator: int): int =
+func foldl*(function: proc(x, y: int): int {.noSideEffect.}, list: seq[int], accumulator: int): int =
   if list.len == 0:
     accumulator
   else:
     foldl(function, list[1..^1], function(accumulator, list[0]))
 
-proc foldr*(function: proc(x, y: int): int, list: seq[int], accumulator: int): int =
+func foldr*(function: proc(x, y: int): int {.noSideEffect.}, list: seq[int], accumulator: int): int =
   if list.len == 0:
     accumulator
   else:
     function(foldr(function, list[1..^1], accumulator), list[0])
 
-proc reverse*(list: seq[int]): seq[int] =
+func reverse*(list: seq[int]): seq[int] =
   result = newSeq[int](list.len)
   for i, x in list:
     result[list.high - i] = x

From d628b5bdd3e86c1b3fa45d0fd050311a9539d652 Mon Sep 17 00:00:00 2001
From: ee7 <45465154+ee7@users.noreply.github.com>
Date: Sat, 27 Jan 2024 14:25:10 +0100
Subject: [PATCH 15/24] exercises(list-ops): example: wrap (now-)long lines

---
 exercises/practice/list-ops/.meta/example.nim | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/exercises/practice/list-ops/.meta/example.nim b/exercises/practice/list-ops/.meta/example.nim
index c3e33fd5..900083e6 100644
--- a/exercises/practice/list-ops/.meta/example.nim
+++ b/exercises/practice/list-ops/.meta/example.nim
@@ -23,13 +23,15 @@ func map*(function: proc(x: int): int {.noSideEffect.}, list: seq[int]): seq[int
   for i, x in list:
     result[i] = function(x)
 
-func foldl*(function: proc(x, y: int): int {.noSideEffect.}, list: seq[int], accumulator: int): int =
+func foldl*(function: proc(x, y: int): int {.noSideEffect.}, list: seq[int],
+            accumulator: int): int =
   if list.len == 0:
     accumulator
   else:
     foldl(function, list[1..^1], function(accumulator, list[0]))
 
-func foldr*(function: proc(x, y: int): int {.noSideEffect.}, list: seq[int], accumulator: int): int =
+func foldr*(function: proc(x, y: int): int {.noSideEffect.}, list: seq[int],
+            accumulator: int): int =
   if list.len == 0:
     accumulator
   else:

From ae8ae1b5dfb97f225daca767469844e56f219ec8 Mon Sep 17 00:00:00 2001
From: ee7 <45465154+ee7@users.noreply.github.com>
Date: Sat, 27 Jan 2024 14:25:11 +0100
Subject: [PATCH 16/24] exercises(list-ops): example: refactor `append`

---
 exercises/practice/list-ops/.meta/example.nim | 12 +++++++++---
 1 file changed, 9 insertions(+), 3 deletions(-)

diff --git a/exercises/practice/list-ops/.meta/example.nim b/exercises/practice/list-ops/.meta/example.nim
index 900083e6..5541c483 100644
--- a/exercises/practice/list-ops/.meta/example.nim
+++ b/exercises/practice/list-ops/.meta/example.nim
@@ -1,8 +1,14 @@
 func append*(list1, list2: seq[int]): seq[int] =
   if list2.len == 0:
-    list1
-  else:
-    append(list1 & list2[0], list2[1..^1])
+    return list1
+  result = newSeq[int](list1.len + list2.len)
+  var i = 0
+  for x in list1:
+    result[i] = x
+    inc i
+  for x in list2:
+    result[i] = x
+    inc i
 
 func concatenate*(lists: seq[seq[int]]): seq[int] =
   result = @[]

From aa8f0366f66a3721b0512ffc663c61350fe31fe3 Mon Sep 17 00:00:00 2001
From: ee7 <45465154+ee7@users.noreply.github.com>
Date: Sat, 27 Jan 2024 14:25:12 +0100
Subject: [PATCH 17/24] exercises(list-ops): tests: prefer to check len == 0

---
 exercises/practice/list-ops/test_list_ops.nim | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/exercises/practice/list-ops/test_list_ops.nim b/exercises/practice/list-ops/test_list_ops.nim
index 8a5fa46a..93060d9d 100644
--- a/exercises/practice/list-ops/test_list_ops.nim
+++ b/exercises/practice/list-ops/test_list_ops.nim
@@ -4,7 +4,7 @@ import list_ops
 
 suite "append entries to a list and return the new list":
   test "empty lists":  # 485b9452-bf94-40f7-a3db-c3cf4850066a
-    check append(@[], @[]) == newSeq[int]()
+    check append(@[], @[]).len == 0
 
   test "list to empty list":  # 2c894696-b609-4569-b149-8672134d340a
     check append(@[], @[1, 2, 3, 4]) == @[1, 2, 3, 4]
@@ -18,7 +18,7 @@ suite "append entries to a list and return the new list":
 
 suite "concatenate a list of lists":
   test "empty list":  # 28444355-201b-4af2-a2f6-5550227bde21
-    check concatenate(@[]) == newSeq[int]()
+    check concatenate(@[]).len == 0
 
   test "list of lists":  # 331451c1-9573-42a1-9869-2d06e3b389a9
     check concatenate(@[@[1, 2], @[3], @[], @[4, 5, 6]]) == @[1, 2, 3, 4, 5, 6]
@@ -31,7 +31,7 @@ suite "filter list returning only values that satisfy the filter function":
   func predicate(x: int): bool = x mod 2 == 1
 
   test "empty list":  # 0524fba8-3e0f-4531-ad2b-f7a43da86a16
-    check filter(predicate, @[]) == newSeq[int]()
+    check filter(predicate, @[]).len == 0
 
   test "non-empty list":  # 88494bd5-f520-4edb-8631-88e415b62d24
     check filter(predicate, @[1, 2, 3, 5]) == @[1, 3, 5]
@@ -49,7 +49,7 @@ suite "return a list of elements whose values equal the list value transformed b
   func function(x: int): int = x + 1
 
   test "empty list":  # c0bc8962-30e2-4bec-9ae4-668b8ecd75aa
-    check map(function, @[]) == newSeq[int]()
+    check map(function, @[]).len == 0
 
   test "non-empty list":  # 11e71a95-e78b-4909-b8e4-60cdcaec0e91
     check map(function, @[1, 3, 5, 7]) == @[2, 4, 6, 8]
@@ -109,7 +109,7 @@ suite "folds (reduces) the given list from the right with a function":
 
 suite "reverse the elements of the list":
   test "empty list":  # 94231515-050e-4841-943d-d4488ab4ee30
-    check reverse(@[]) == newSeq[int]()
+    check reverse(@[]).len == 0
 
   test "non-empty list":  # fcc03d1e-42e0-4712-b689-d54ad761f360
     check reverse(@[1, 2, 3, 4]) == @[4, 3, 2, 1]

From 54aa4e70dc7159dff6833c99973c82cded4e4c6a Mon Sep 17 00:00:00 2001
From: ee7 <45465154+ee7@users.noreply.github.com>
Date: Sat, 27 Jan 2024 14:25:13 +0100
Subject: [PATCH 18/24] exercises(list-ops): example: prefer openArray

---
 exercises/practice/list-ops/.meta/example.nim | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/exercises/practice/list-ops/.meta/example.nim b/exercises/practice/list-ops/.meta/example.nim
index 5541c483..5962faae 100644
--- a/exercises/practice/list-ops/.meta/example.nim
+++ b/exercises/practice/list-ops/.meta/example.nim
@@ -10,40 +10,40 @@ func append*(list1, list2: seq[int]): seq[int] =
     result[i] = x
     inc i
 
-func concatenate*(lists: seq[seq[int]]): seq[int] =
+func concatenate*(lists: openArray[seq[int]]): seq[int] =
   result = @[]
   for list in lists:
     result = append(result, list)
 
-func filter*(predicate: proc(x: int): bool {.noSideEffect.}, list: seq[int]): seq[int] =
+func filter*(predicate: proc(x: int): bool {.noSideEffect.}, list: openArray[int]): seq[int] =
   result = @[]
   for x in list:
     if predicate(x):
       result.add x
 
-func length*(list: seq[int]): int =
+func length*(list: openArray[int]): int =
   list.len
 
-func map*(function: proc(x: int): int {.noSideEffect.}, list: seq[int]): seq[int] =
+func map*(function: proc(x: int): int {.noSideEffect.}, list: openArray[int]): seq[int] =
   result = newSeq[int](list.len)
   for i, x in list:
     result[i] = function(x)
 
-func foldl*(function: proc(x, y: int): int {.noSideEffect.}, list: seq[int],
+func foldl*(function: proc(x, y: int): int {.noSideEffect.}, list: openArray[int],
             accumulator: int): int =
   if list.len == 0:
     accumulator
   else:
     foldl(function, list[1..^1], function(accumulator, list[0]))
 
-func foldr*(function: proc(x, y: int): int {.noSideEffect.}, list: seq[int],
+func foldr*(function: proc(x, y: int): int {.noSideEffect.}, list: openArray[int],
             accumulator: int): int =
   if list.len == 0:
     accumulator
   else:
     function(foldr(function, list[1..^1], accumulator), list[0])
 
-func reverse*(list: seq[int]): seq[int] =
+func reverse*(list: openArray[int]): seq[int] =
   result = newSeq[int](list.len)
   for i, x in list:
     result[list.high - i] = x

From cea855e707fec256aff4e99a8f9ffb6184420684 Mon Sep 17 00:00:00 2001
From: ee7 <45465154+ee7@users.noreply.github.com>
Date: Sat, 27 Jan 2024 14:25:14 +0100
Subject: [PATCH 19/24] exercises(list-ops): example, stub, test: write `list`
 first

Support the method call syntax [1].

[1] https://nim-lang.org/docs/manual.html#procedures-method-call-syntax
---
 exercises/practice/list-ops/.meta/example.nim | 12 +++----
 exercises/practice/list-ops/list_ops.nim      |  8 ++---
 exercises/practice/list-ops/test_list_ops.nim | 32 +++++++++----------
 3 files changed, 26 insertions(+), 26 deletions(-)

diff --git a/exercises/practice/list-ops/.meta/example.nim b/exercises/practice/list-ops/.meta/example.nim
index 5962faae..e29b45fe 100644
--- a/exercises/practice/list-ops/.meta/example.nim
+++ b/exercises/practice/list-ops/.meta/example.nim
@@ -15,7 +15,7 @@ func concatenate*(lists: openArray[seq[int]]): seq[int] =
   for list in lists:
     result = append(result, list)
 
-func filter*(predicate: proc(x: int): bool {.noSideEffect.}, list: openArray[int]): seq[int] =
+func filter*(list: openArray[int], predicate: proc(x: int): bool {.noSideEffect.}): seq[int] =
   result = @[]
   for x in list:
     if predicate(x):
@@ -24,24 +24,24 @@ func filter*(predicate: proc(x: int): bool {.noSideEffect.}, list: openArray[int
 func length*(list: openArray[int]): int =
   list.len
 
-func map*(function: proc(x: int): int {.noSideEffect.}, list: openArray[int]): seq[int] =
+func map*(list: openArray[int], function: proc(x: int): int {.noSideEffect.}): seq[int] =
   result = newSeq[int](list.len)
   for i, x in list:
     result[i] = function(x)
 
-func foldl*(function: proc(x, y: int): int {.noSideEffect.}, list: openArray[int],
+func foldl*(list: openArray[int], function: proc(x, y: int): int {.noSideEffect.},
             accumulator: int): int =
   if list.len == 0:
     accumulator
   else:
-    foldl(function, list[1..^1], function(accumulator, list[0]))
+    foldl(list[1..^1], function, function(accumulator, list[0]))
 
-func foldr*(function: proc(x, y: int): int {.noSideEffect.}, list: openArray[int],
+func foldr*(list: openArray[int], function: proc(x, y: int): int {.noSideEffect.},
             accumulator: int): int =
   if list.len == 0:
     accumulator
   else:
-    function(foldr(function, list[1..^1], accumulator), list[0])
+    function(foldr(list[1..^1], function, accumulator), list[0])
 
 func reverse*(list: openArray[int]): seq[int] =
   result = newSeq[int](list.len)
diff --git a/exercises/practice/list-ops/list_ops.nim b/exercises/practice/list-ops/list_ops.nim
index 34c75a86..459ecaf8 100644
--- a/exercises/practice/list-ops/list_ops.nim
+++ b/exercises/practice/list-ops/list_ops.nim
@@ -4,19 +4,19 @@ proc append*(list1, list2: seq[int]): seq[int] =
 proc concatenate*(lists: seq[seq[int]]): seq[int] =
   discard
 
-proc filter*(predicate: proc(x: int): bool, list: seq[int]): seq[int] =
+proc filter*(list: seq[int], predicate: proc(x: int): bool): seq[int] =
   discard
 
 proc length*(list: seq[int]): int =
   discard
 
-proc map*(function: proc(x: int): int, list: seq[int]): seq[int] =
+proc map*(list: seq[int], function: proc(x: int): int): seq[int] =
   discard
 
-proc foldl*(function: proc(x, y: int): int, list: seq[int], accumulator: int): int =
+proc foldl*(list: seq[int], function: proc(x, y: int): int, accumulator: int): int =
   discard
 
-proc foldr*(function: proc(x, y: int): int, list: seq[int], accumulator: int): int =
+proc foldr*(list: seq[int], function: proc(x, y: int): int, accumulator: int): int =
   discard
 
 proc reverse*(list: seq[int]): seq[int] =
diff --git a/exercises/practice/list-ops/test_list_ops.nim b/exercises/practice/list-ops/test_list_ops.nim
index 93060d9d..7eae7f6d 100644
--- a/exercises/practice/list-ops/test_list_ops.nim
+++ b/exercises/practice/list-ops/test_list_ops.nim
@@ -31,10 +31,10 @@ suite "filter list returning only values that satisfy the filter function":
   func predicate(x: int): bool = x mod 2 == 1
 
   test "empty list":  # 0524fba8-3e0f-4531-ad2b-f7a43da86a16
-    check filter(predicate, @[]).len == 0
+    check filter(@[], predicate).len == 0
 
   test "non-empty list":  # 88494bd5-f520-4edb-8631-88e415b62d24
-    check filter(predicate, @[1, 2, 3, 5]) == @[1, 3, 5]
+    check filter(@[1, 2, 3, 5], predicate) == @[1, 3, 5]
 
 
 suite "returns the length of a list":
@@ -49,62 +49,62 @@ suite "return a list of elements whose values equal the list value transformed b
   func function(x: int): int = x + 1
 
   test "empty list":  # c0bc8962-30e2-4bec-9ae4-668b8ecd75aa
-    check map(function, @[]).len == 0
+    check map(@[], function).len == 0
 
   test "non-empty list":  # 11e71a95-e78b-4909-b8e4-60cdcaec0e91
-    check map(function, @[1, 3, 5, 7]) == @[2, 4, 6, 8]
+    check map(@[1, 3, 5, 7], function) == @[2, 4, 6, 8]
 
 
 suite "folds (reduces) the given list from the left with a function":
   test "empty list":  # 613b20b7-1873-4070-a3a6-70ae5f50d7cc
     func function(x: int, y: int): int = x + y
-    check foldl(function, @[], 2) == 2
+    check foldl(@[], function, 2) == 2
 
   test "direction independent function applied to non-empty list":  # e56df3eb-9405-416a-b13a-aabb4c3b5194
     func function(x: int, y: int): int = x + y
-    check foldl(function, @[1, 2, 3, 4], 5) == 15
+    check foldl(@[1, 2, 3, 4], function, 5) == 15
 
   test "direction dependent function applied to non-empty list":  # d2cf5644-aee1-4dfc-9b88-06896676fe27
     func function(x: int, y: int): int | float = x - y
-    check foldl(function, @[1, 2, 3, 4], 24) == 14
+    check foldl(@[1, 2, 3, 4], function, 24) == 14
 
   test "empty list":  # 36549237-f765-4a4c-bfd9-5d3a8f7b07d2
     func function(x: int, y: int): int = y + x
-    check foldl(function, @[], 2) == 2
+    check foldl(@[], function, 2) == 2
 
   test "direction independent function applied to non-empty list":  # 7a626a3c-03ec-42bc-9840-53f280e13067
     func function(x: int, y: int): int = y + x
-    check foldl(function, @[1, 2, 3, 4], 5) == 15
+    check foldl(@[1, 2, 3, 4], function, 5) == 15
 
   test "direction dependent function applied to non-empty list":  # d7fcad99-e88e-40e1-a539-4c519681f390
     func function(x: int, y: int): int = y - x
-    check foldl(function, @[1, 2, 3, 4], 5) == 7
+    check foldl(@[1, 2, 3, 4], function, 5) == 7
 
 
 suite "folds (reduces) the given list from the right with a function":
   test "empty list":  # aeb576b9-118e-4a57-a451-db49fac20fdc
     func function(x: int, y: int): int = x + y
-    check foldr(function, @[], 2) == 2
+    check foldr(@[], function, 2) == 2
 
   test "direction independent function applied to non-empty list":  # c4b64e58-313e-4c47-9c68-7764964efb8e
     func function(x: int, y: int): int = x + y
-    check foldr(function, @[1, 2, 3, 4], 5) == 15
+    check foldr(@[1, 2, 3, 4], function, 5) == 15
 
   test "direction dependent function applied to non-empty list":  # be396a53-c074-4db3-8dd6-f7ed003cce7c
     func function(x: int, y: int): int | float = x - y
-    check foldr(function, @[1, 2, 3, 4], 24) == 14
+    check foldr(@[1, 2, 3, 4], function, 24) == 14
 
   test "empty list":  # 17214edb-20ba-42fc-bda8-000a5ab525b0
     func function(x: int, y: int): int = y + x
-    check foldr(function, @[], 2) == 2
+    check foldr(@[], function, 2) == 2
 
   test "direction independent function applied to non-empty list":  # e1c64db7-9253-4a3d-a7c4-5273b9e2a1bd
     func function(x: int, y: int): int = y + x
-    check foldr(function, @[1, 2, 3, 4], 5) == 15
+    check foldr(@[1, 2, 3, 4], function, 5) == 15
 
   test "direction dependent function applied to non-empty list":  # 8066003b-f2ff-437e-9103-66e6df474844
     func function(x: int, y: int): int = y - x
-    check foldr(function, @[1, 2, 3, 4], 5) == 3
+    check foldr(@[1, 2, 3, 4], function, 5) == 3
 
 
 suite "reverse the elements of the list":

From 42896c8d9dcd27645126fc074e9218211273f69b Mon Sep 17 00:00:00 2001
From: ee7 <45465154+ee7@users.noreply.github.com>
Date: Sat, 27 Jan 2024 14:25:15 +0100
Subject: [PATCH 20/24] exercises(list-ops): tests: remove unimplemented test
 cases

---
 exercises/practice/list-ops/test_list_ops.nim | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/exercises/practice/list-ops/test_list_ops.nim b/exercises/practice/list-ops/test_list_ops.nim
index 7eae7f6d..e03e7147 100644
--- a/exercises/practice/list-ops/test_list_ops.nim
+++ b/exercises/practice/list-ops/test_list_ops.nim
@@ -23,9 +23,6 @@ suite "concatenate a list of lists":
   test "list of lists":  # 331451c1-9573-42a1-9869-2d06e3b389a9
     check concatenate(@[@[1, 2], @[3], @[], @[4, 5, 6]]) == @[1, 2, 3, 4, 5, 6]
 
-  # test "list of nested lists":  # d6ecd72c-197f-40c3-89a4-aa1f45827e09
-  #   check concatenate(@[@[@[1], @[2]], @[@[3]], @[@[]], @[@[4, 5, 6]]]) == @[@[1], @[2], @[3], @[], @[4, 5, 6]]
-
 
 suite "filter list returning only values that satisfy the filter function":
   func predicate(x: int): bool = x mod 2 == 1
@@ -113,6 +110,3 @@ suite "reverse the elements of the list":
 
   test "non-empty list":  # fcc03d1e-42e0-4712-b689-d54ad761f360
     check reverse(@[1, 2, 3, 4]) == @[4, 3, 2, 1]
-
-  # test "list of lists is not flattened":  # 40872990-b5b8-4cb8-9085-d91fc0d05d26
-    # check reverse(@[@[], @[1], @[2, 3]]) == @[@[2, 3], @[1], @[]]

From f945be9e6d6f33ede4663335b6215ef666d36028 Mon Sep 17 00:00:00 2001
From: ee7 <45465154+ee7@users.noreply.github.com>
Date: Sat, 27 Jan 2024 14:25:16 +0100
Subject: [PATCH 21/24] exercises(list-ops): tests: remove UUID comments

---
 exercises/practice/list-ops/test_list_ops.nim | 52 +++++++++----------
 1 file changed, 26 insertions(+), 26 deletions(-)

diff --git a/exercises/practice/list-ops/test_list_ops.nim b/exercises/practice/list-ops/test_list_ops.nim
index e03e7147..17fe4416 100644
--- a/exercises/practice/list-ops/test_list_ops.nim
+++ b/exercises/practice/list-ops/test_list_ops.nim
@@ -3,110 +3,110 @@ import list_ops
 
 
 suite "append entries to a list and return the new list":
-  test "empty lists":  # 485b9452-bf94-40f7-a3db-c3cf4850066a
+  test "empty lists":
     check append(@[], @[]).len == 0
 
-  test "list to empty list":  # 2c894696-b609-4569-b149-8672134d340a
+  test "list to empty list":
     check append(@[], @[1, 2, 3, 4]) == @[1, 2, 3, 4]
 
-  test "empty list to list":  # e842efed-3bf6-4295-b371-4d67a4fdf19c
+  test "empty list to list":
     check append(@[1, 2, 3, 4], @[]) == @[1, 2, 3, 4]
 
-  test "non-empty lists":  # 71dcf5eb-73ae-4a0e-b744-a52ee387922f
+  test "non-empty lists":
     check append(@[1, 2], @[2, 3, 4, 5]) == @[1, 2, 2, 3, 4, 5]
 
 
 suite "concatenate a list of lists":
-  test "empty list":  # 28444355-201b-4af2-a2f6-5550227bde21
+  test "empty list":
     check concatenate(@[]).len == 0
 
-  test "list of lists":  # 331451c1-9573-42a1-9869-2d06e3b389a9
+  test "list of lists":
     check concatenate(@[@[1, 2], @[3], @[], @[4, 5, 6]]) == @[1, 2, 3, 4, 5, 6]
 
 
 suite "filter list returning only values that satisfy the filter function":
   func predicate(x: int): bool = x mod 2 == 1
 
-  test "empty list":  # 0524fba8-3e0f-4531-ad2b-f7a43da86a16
+  test "empty list":
     check filter(@[], predicate).len == 0
 
-  test "non-empty list":  # 88494bd5-f520-4edb-8631-88e415b62d24
+  test "non-empty list":
     check filter(@[1, 2, 3, 5], predicate) == @[1, 3, 5]
 
 
 suite "returns the length of a list":
-  test "empty list":  # 1cf0b92d-8d96-41d5-9c21-7b3c37cb6aad
+  test "empty list":
     check length(@[]) == 0
 
-  test "non-empty list":  # d7b8d2d9-2d16-44c4-9a19-6e5f237cb71e
+  test "non-empty list":
     check length(@[1, 2, 3, 4]) == 4
 
 
 suite "return a list of elements whose values equal the list value transformed by the mapping function":
   func function(x: int): int = x + 1
 
-  test "empty list":  # c0bc8962-30e2-4bec-9ae4-668b8ecd75aa
+  test "empty list":
     check map(@[], function).len == 0
 
-  test "non-empty list":  # 11e71a95-e78b-4909-b8e4-60cdcaec0e91
+  test "non-empty list":
     check map(@[1, 3, 5, 7], function) == @[2, 4, 6, 8]
 
 
 suite "folds (reduces) the given list from the left with a function":
-  test "empty list":  # 613b20b7-1873-4070-a3a6-70ae5f50d7cc
+  test "empty list":
     func function(x: int, y: int): int = x + y
     check foldl(@[], function, 2) == 2
 
-  test "direction independent function applied to non-empty list":  # e56df3eb-9405-416a-b13a-aabb4c3b5194
+  test "direction independent function applied to non-empty list":
     func function(x: int, y: int): int = x + y
     check foldl(@[1, 2, 3, 4], function, 5) == 15
 
-  test "direction dependent function applied to non-empty list":  # d2cf5644-aee1-4dfc-9b88-06896676fe27
+  test "direction dependent function applied to non-empty list":
     func function(x: int, y: int): int | float = x - y
     check foldl(@[1, 2, 3, 4], function, 24) == 14
 
-  test "empty list":  # 36549237-f765-4a4c-bfd9-5d3a8f7b07d2
+  test "empty list":
     func function(x: int, y: int): int = y + x
     check foldl(@[], function, 2) == 2
 
-  test "direction independent function applied to non-empty list":  # 7a626a3c-03ec-42bc-9840-53f280e13067
+  test "direction independent function applied to non-empty list":
     func function(x: int, y: int): int = y + x
     check foldl(@[1, 2, 3, 4], function, 5) == 15
 
-  test "direction dependent function applied to non-empty list":  # d7fcad99-e88e-40e1-a539-4c519681f390
+  test "direction dependent function applied to non-empty list":
     func function(x: int, y: int): int = y - x
     check foldl(@[1, 2, 3, 4], function, 5) == 7
 
 
 suite "folds (reduces) the given list from the right with a function":
-  test "empty list":  # aeb576b9-118e-4a57-a451-db49fac20fdc
+  test "empty list":
     func function(x: int, y: int): int = x + y
     check foldr(@[], function, 2) == 2
 
-  test "direction independent function applied to non-empty list":  # c4b64e58-313e-4c47-9c68-7764964efb8e
+  test "direction independent function applied to non-empty list":
     func function(x: int, y: int): int = x + y
     check foldr(@[1, 2, 3, 4], function, 5) == 15
 
-  test "direction dependent function applied to non-empty list":  # be396a53-c074-4db3-8dd6-f7ed003cce7c
+  test "direction dependent function applied to non-empty list":
     func function(x: int, y: int): int | float = x - y
     check foldr(@[1, 2, 3, 4], function, 24) == 14
 
-  test "empty list":  # 17214edb-20ba-42fc-bda8-000a5ab525b0
+  test "empty list":
     func function(x: int, y: int): int = y + x
     check foldr(@[], function, 2) == 2
 
-  test "direction independent function applied to non-empty list":  # e1c64db7-9253-4a3d-a7c4-5273b9e2a1bd
+  test "direction independent function applied to non-empty list":
     func function(x: int, y: int): int = y + x
     check foldr(@[1, 2, 3, 4], function, 5) == 15
 
-  test "direction dependent function applied to non-empty list":  # 8066003b-f2ff-437e-9103-66e6df474844
+  test "direction dependent function applied to non-empty list":
     func function(x: int, y: int): int = y - x
     check foldr(@[1, 2, 3, 4], function, 5) == 3
 
 
 suite "reverse the elements of the list":
-  test "empty list":  # 94231515-050e-4841-943d-d4488ab4ee30
+  test "empty list":
     check reverse(@[]).len == 0
 
-  test "non-empty list":  # fcc03d1e-42e0-4712-b689-d54ad761f360
+  test "non-empty list":
     check reverse(@[1, 2, 3, 4]) == @[4, 3, 2, 1]

From ecf1542e3f3cc59bf2e51fef96dd4361247e441f Mon Sep 17 00:00:00 2001
From: ee7 <45465154+ee7@users.noreply.github.com>
Date: Sat, 27 Jan 2024 14:25:17 +0100
Subject: [PATCH 22/24] exercises(list-ops): tests: remove float from return
 type

---
 exercises/practice/list-ops/test_list_ops.nim | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/exercises/practice/list-ops/test_list_ops.nim b/exercises/practice/list-ops/test_list_ops.nim
index 17fe4416..4973ff75 100644
--- a/exercises/practice/list-ops/test_list_ops.nim
+++ b/exercises/practice/list-ops/test_list_ops.nim
@@ -62,7 +62,7 @@ suite "folds (reduces) the given list from the left with a function":
     check foldl(@[1, 2, 3, 4], function, 5) == 15
 
   test "direction dependent function applied to non-empty list":
-    func function(x: int, y: int): int | float = x - y
+    func function(x: int, y: int): int = x - y
     check foldl(@[1, 2, 3, 4], function, 24) == 14
 
   test "empty list":
@@ -88,7 +88,7 @@ suite "folds (reduces) the given list from the right with a function":
     check foldr(@[1, 2, 3, 4], function, 5) == 15
 
   test "direction dependent function applied to non-empty list":
-    func function(x: int, y: int): int | float = x - y
+    func function(x: int, y: int): int = x - y
     check foldr(@[1, 2, 3, 4], function, 24) == 14
 
   test "empty list":

From 231798df0053a2d78dc0d195cef7b80c0bbf2ae3 Mon Sep 17 00:00:00 2001
From: ee7 <45465154+ee7@users.noreply.github.com>
Date: Sat, 27 Jan 2024 14:25:18 +0100
Subject: [PATCH 23/24] exercises(list-ops): example: use `toOpenArray`, not
 slicing

---
 exercises/practice/list-ops/.meta/example.nim | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/exercises/practice/list-ops/.meta/example.nim b/exercises/practice/list-ops/.meta/example.nim
index e29b45fe..bbca1933 100644
--- a/exercises/practice/list-ops/.meta/example.nim
+++ b/exercises/practice/list-ops/.meta/example.nim
@@ -34,14 +34,14 @@ func foldl*(list: openArray[int], function: proc(x, y: int): int {.noSideEffect.
   if list.len == 0:
     accumulator
   else:
-    foldl(list[1..^1], function, function(accumulator, list[0]))
+    foldl(list.toOpenArray(1, list.high), function, function(accumulator, list[0]))
 
 func foldr*(list: openArray[int], function: proc(x, y: int): int {.noSideEffect.},
             accumulator: int): int =
   if list.len == 0:
     accumulator
   else:
-    function(foldr(list[1..^1], function, accumulator), list[0])
+    function(foldr(list.toOpenArray(1, list.high), function, accumulator), list[0])
 
 func reverse*(list: openArray[int]): seq[int] =
   result = newSeq[int](list.len)

From ce422d4eb99535cd1b1465d570bdca9f6b6e7b27 Mon Sep 17 00:00:00 2001
From: ee7 <45465154+ee7@users.noreply.github.com>
Date: Sat, 27 Jan 2024 14:25:19 +0100
Subject: [PATCH 24/24] exercises(list-ops): tests.toml: exclude unimplemented
 test cases

---
 exercises/practice/list-ops/.meta/tests.toml | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/exercises/practice/list-ops/.meta/tests.toml b/exercises/practice/list-ops/.meta/tests.toml
index 16a0fca6..203ce1e3 100644
--- a/exercises/practice/list-ops/.meta/tests.toml
+++ b/exercises/practice/list-ops/.meta/tests.toml
@@ -27,8 +27,9 @@ description = "concatenate a list of lists -> empty list"
 [331451c1-9573-42a1-9869-2d06e3b389a9]
 description = "concatenate a list of lists -> list of lists"
 
-# [d6ecd72c-197f-40c3-89a4-aa1f45827e09]
-# description = "concatenate a list of lists -> list of nested lists"
+[d6ecd72c-197f-40c3-89a4-aa1f45827e09]
+description = "concatenate a list of lists -> list of nested lists"
+include = false
 
 [0524fba8-3e0f-4531-ad2b-f7a43da86a16]
 description = "filter list returning only values that satisfy the filter function -> empty list"
@@ -102,5 +103,6 @@ description = "reverse the elements of the list -> empty list"
 [fcc03d1e-42e0-4712-b689-d54ad761f360]
 description = "reverse the elements of the list -> non-empty list"
 
-# [40872990-b5b8-4cb8-9085-d91fc0d05d26]
-# description = "reverse the elements of the list -> list of lists is not flattened"
+[40872990-b5b8-4cb8-9085-d91fc0d05d26]
+description = "reverse the elements of the list -> list of lists is not flattened"
+include = false