Skip to content

Commit

Permalink
Exercise list ops Use List.append instead of List.prepend (#128)
Browse files Browse the repository at this point in the history
* Exercise list ops

Use List.append instead of List.prepend

* Short explenation and more tail recursion

* adjust wording

---------

Co-authored-by: Isaac Van Doren <69181572+isaacvando@users.noreply.github.com>
  • Loading branch information
ostcar and isaacvando authored Oct 2, 2024
1 parent 5a3716e commit e6d3bb7
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 27 deletions.
13 changes: 10 additions & 3 deletions exercises/practice/list-ops/.docs/instructions.append.md
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -22,4 +29,4 @@ or
when list is
[] -> ???
[.. as rest, last] -> ???
```
```
59 changes: 35 additions & 24 deletions exercises/practice/list-ops/.meta/Example.roc
Original file line number Diff line number Diff line change
Expand Up @@ -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 []

0 comments on commit e6d3bb7

Please sign in to comment.