diff --git a/exercises/practice/list-ops/.docs/instructions.append.md b/exercises/practice/list-ops/.docs/instructions.append.md index 10d67b3..1ef8e76 100644 --- a/exercises/practice/list-ops/.docs/instructions.append.md +++ b/exercises/practice/list-ops/.docs/instructions.append.md @@ -1,13 +1,20 @@ # Wait, It's Impossible! -Implementing these list operations without using *any* built-in function is + +Implementing these list operations without using _any_ built-in function is virtually impossible in Roc, because you need a way to append or prepend elements to a list. In other languages you might use operators such as `:` in Haskell or `+=` in Python, but in Roc you have to use the [`List` functions](https://www.roc-lang.org/builtins/List). -So for this exercise you're allowed to use `List.prepend` (but avoid using any +So for this exercise you're allowed to use `List.append` (but avoid using any other built-in function). +Many functional programming languages use linked lists as the primary collection type. +It is efficient to prepend an element or pop the first element from a linked list, so in those languages, you would implement list operations +using `List.prepend`. In Roc however, a `List` is an array (a contiguous chunk of bytes). Arrays have different +properties than linked lists like the ability to efficiently access elements by index and append new elements. +Because of this, in Roc we use `List.append` often and rarely use `List.prepend`. + Hint: try using: ```roc @@ -22,4 +29,4 @@ or when list is [] -> ??? [.. as rest, last] -> ??? -``` \ No newline at end of file +``` diff --git a/exercises/practice/list-ops/.meta/Example.roc b/exercises/practice/list-ops/.meta/Example.roc index 45145e5..0583808 100644 --- a/exercises/practice/list-ops/.meta/Example.roc +++ b/exercises/practice/list-ops/.meta/Example.roc @@ -3,58 +3,69 @@ module [append, concat, filter, length, map, foldl, foldr, reverse] append : List a, List a -> List a append = \list1, list2 -> # Cheating: list1 |> List.concat list2 - when list1 is - [] -> list2 - [first, .. as rest] -> (append rest list2) |> List.prepend first + when list2 is + [] -> list1 + [first, .. as rest] -> list1 |> List.append first |> append rest concat : List (List a) -> List a concat = \lists -> + # Cheating: list |> List.join when lists is [] -> [] - [sublist1, .. as rest] -> sublist1 |> append (concat rest) + [one] -> one + [.. as rest, one, two] -> rest |> List.append (append one two) |> concat filter : List a, (a -> Bool) -> List a filter = \list, function -> # Cheating: list |> List.keepIf function - when list is - [] -> [] - [first, .. as rest] -> - if function first then - filter rest function |> List.prepend first - else - filter rest function + loop = \l, acc -> + when l is + [] -> acc + [first, .. as rest] -> + if function first then + rest |> loop (List.append acc first) + else + rest |> loop acc + + loop list [] length : List a -> U64 length = \list -> - # Cheating: List.len list - when list is - [] -> 0 - [_, .. as rest] -> 1 + length rest + # Cheating: list |> List.len + loop = \l, acc -> + when l is + [] -> acc + [_, .. as rest] -> rest |> loop (acc + 1) + loop list 0 map : List a, (a -> b) -> List b map = \list, function -> # Cheating: list |> List.map function - when list is - [] -> [] - [first, .. as rest] -> map rest function |> List.prepend (function first) + loop = \l, acc -> + when l is + [] -> acc + [first, .. as rest] -> rest |> loop (List.append acc (function first)) + loop list [] foldl : List a, b, (b, a -> b) -> b foldl = \list, initial, function -> # Cheating: list |> List.walk initial function when list is [] -> initial - [first, .. as rest] -> foldl rest (function initial first) function + [first, .. as rest] -> rest |> foldl (function initial first) function foldr : List a, b, (b, a -> b) -> b foldr = \list, initial, function -> # Cheating: list |> List.walkBackwards initial function when list is [] -> initial - [.. as rest, last] -> foldr rest (function initial last) function + [.. as rest, last] -> rest |> foldr (function initial last) function reverse : List a -> List a reverse = \list -> - # Cheating: List.reverse list - when list is - [] -> [] - [.. as rest, last] -> reverse rest |> List.prepend last + # Cheating: list |> List.reverse + loop = \l, acc -> + when l is + [] -> acc + [.. as rest, last] -> rest |> loop (List.append acc last) + loop list []