diff options
author | Louis Pilfold <louis@lpil.uk> | 2021-09-11 18:03:27 +0100 |
---|---|---|
committer | Louis Pilfold <louis@lpil.uk> | 2021-09-11 18:03:28 +0100 |
commit | f083720d6eaf1c68a7f70dfb168fd2a431671b25 (patch) | |
tree | a9569d039111a300aa30e6ddf9e5523efcb9ea19 | |
parent | 2ca0b25d3841dee7e12d3ae39520f8339fd1d5b7 (diff) | |
download | gleam_stdlib-f083720d6eaf1c68a7f70dfb168fd2a431671b25.tar.gz gleam_stdlib-f083720d6eaf1c68a7f70dfb168fd2a431671b25.zip |
Flip arguments of reducers
Closes https://github.com/gleam-lag/gleam/issues/1258
-rw-r--r-- | CHANGELOG.md | 5 | ||||
-rw-r--r-- | src/gleam/bit_builder.gleam | 2 | ||||
-rw-r--r-- | src/gleam/iterator.gleam | 99 | ||||
-rw-r--r-- | src/gleam/list.gleam | 84 | ||||
-rw-r--r-- | src/gleam/map.gleam | 28 | ||||
-rw-r--r-- | src/gleam/option.gleam | 2 | ||||
-rw-r--r-- | src/gleam/set.gleam | 8 | ||||
-rw-r--r-- | test/gleam/iterator_test.gleam | 35 | ||||
-rw-r--r-- | test/gleam/list_test.gleam | 18 | ||||
-rw-r--r-- | test/gleam/map_test.gleam | 4 |
10 files changed, 138 insertions, 147 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index a0e8c68..be4f8de 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,11 @@ - The `should` module has been moved to the `gleam_should_assertions` package. - The `uri.percent_encode` function has a slightly different behaviour. For example spaces are encoded as `%20`, not as `+`. +- The order of the arguments of the the function accepted by the + `list.map_fold`, `list.fold`, `list.fold_right`, `list.index_fold`, + `list.try_fold`, `list.fold_until`, `list.reduce`, `list.scan`, `map.fold`, + `set.fold`, `iterator.fold`, `iterator.scan`, `iterator.reduce`, + `iterator.fold_until`, and `iterator.try_fold` have been flipped. ## v0.16.0 - 2021-06-17 diff --git a/src/gleam/bit_builder.gleam b/src/gleam/bit_builder.gleam index 493addd..fc8ec64 100644 --- a/src/gleam/bit_builder.gleam +++ b/src/gleam/bit_builder.gleam @@ -254,6 +254,6 @@ if javascript { fn do_byte_size(builder: BitBuilder) -> Int { [[builder]] |> to_list([]) - |> list.fold(0, fn(builder, acc) { bit_string.byte_size(builder) + acc }) + |> list.fold(0, fn(acc, builder) { bit_string.byte_size(builder) + acc }) } } diff --git a/src/gleam/iterator.gleam b/src/gleam/iterator.gleam index 32bc960..05bf331 100644 --- a/src/gleam/iterator.gleam +++ b/src/gleam/iterator.gleam @@ -1,9 +1,6 @@ import gleam/list - -if erlang { - import gleam/option.{None, Option, Some} - import gleam/map.{Map} -} +import gleam/option.{None, Option, Some} +import gleam/map.{Map} // Internal private representation of an Iterator type Action(element) { @@ -119,11 +116,11 @@ pub fn from_list(list: List(element)) -> Iterator(element) { // Consuming Iterators fn do_fold( continuation: fn() -> Action(e), - f: fn(e, acc) -> acc, + f: fn(acc, e) -> acc, accumulator: acc, ) -> acc { case continuation() { - Continue(elem, next) -> do_fold(next, f, f(elem, accumulator)) + Continue(elem, next) -> do_fold(next, f, f(accumulator, elem)) Stop -> accumulator } } @@ -147,7 +144,7 @@ fn do_fold( pub fn fold( over iterator: Iterator(e), from initial: acc, - with f: fn(e, acc) -> acc, + with f: fn(acc, e) -> acc, ) -> acc { iterator.continuation |> do_fold(f, initial) @@ -174,7 +171,7 @@ pub fn run(iterator: Iterator(e)) -> Nil { /// pub fn to_list(iterator: Iterator(element)) -> List(element) { iterator - |> fold([], fn(e, acc) { [e, ..acc] }) + |> fold([], fn(acc, e) { [e, ..acc] }) |> list.reverse } @@ -583,14 +580,14 @@ pub fn drop_while( fn do_scan( continuation: fn() -> Action(element), - f: fn(element, acc) -> acc, + f: fn(acc, element) -> acc, accumulator: acc, ) -> fn() -> Action(acc) { fn() { case continuation() { Stop -> Stop Continue(el, next) -> { - let accumulated = f(el, accumulator) + let accumulated = f(accumulator, el) Continue(accumulated, do_scan(next, f, accumulated)) } } @@ -610,7 +607,7 @@ fn do_scan( pub fn scan( over iterator: Iterator(element), from initial: acc, - with f: fn(element, acc) -> acc, + with f: fn(acc, element) -> acc, ) -> Iterator(acc) { iterator.continuation |> do_scan(f, initial) @@ -883,45 +880,41 @@ pub fn all( |> do_all(predicate) } -if erlang { - fn update_group_with( - el: element, - ) -> fn(Option(List(element))) -> List(element) { - fn(maybe_group) { - case maybe_group { - Some(group) -> [el, ..group] - None -> [el] - } +fn update_group_with(el: element) -> fn(Option(List(element))) -> List(element) { + fn(maybe_group) { + case maybe_group { + Some(group) -> [el, ..group] + None -> [el] } } +} - fn group_updater( - f: fn(element) -> key, - ) -> fn(element, Map(key, List(element))) -> Map(key, List(element)) { - fn(elem, groups) { - groups - |> map.update(f(elem), update_group_with(elem)) - } +fn group_updater( + f: fn(element) -> key, +) -> fn(Map(key, List(element)), element) -> Map(key, List(element)) { + fn(groups, elem) { + groups + |> map.update(f(elem), update_group_with(elem)) } +} - /// Returns a `Map(k, List(element))` of elements from the given iterator - /// grouped with the given key function. - /// - /// The order within each group is preserved from the iterator. - /// - /// ## Examples - /// - /// > from_list([1, 2, 3, 4, 5, 6]) |> group(by: fn(n) { n % 3 }) - /// map.from_list([#(0, [3, 6]), #(1, [1, 4]), #(2, [2, 5])]) - /// - pub fn group( - in iterator: Iterator(element), - by key: fn(element) -> key, - ) -> Map(key, List(element)) { - iterator - |> fold(map.new(), group_updater(key)) - |> map.map_values(fn(_, group) { list.reverse(group) }) - } +/// Returns a `Map(k, List(element))` of elements from the given iterator +/// grouped with the given key function. +/// +/// The order within each group is preserved from the iterator. +/// +/// ## Examples +/// +/// > from_list([1, 2, 3, 4, 5, 6]) |> group(by: fn(n) { n % 3 }) +/// map.from_list([#(0, [3, 6]), #(1, [1, 4]), #(2, [2, 5])]) +/// +pub fn group( + in iterator: Iterator(element), + by key: fn(element) -> key, +) -> Map(key, List(element)) { + iterator + |> fold(map.new(), group_updater(key)) + |> map.map_values(fn(_, group) { list.reverse(group) }) } /// This function acts similar to fold, but does not take an initial state. @@ -967,7 +960,7 @@ pub fn reduce( /// pub fn last(iterator: Iterator(element)) -> Result(element, Nil) { iterator - |> reduce(fn(elem, _) { elem }) + |> reduce(fn(_, elem) { elem }) } /// Creates an iterator that yields no elements. @@ -1036,13 +1029,13 @@ pub fn interleave( fn do_fold_until( continuation: fn() -> Action(e), - f: fn(e, acc) -> list.ContinueOrStop(acc), + f: fn(acc, e) -> list.ContinueOrStop(acc), accumulator: acc, ) -> acc { case continuation() { Stop -> accumulator Continue(elem, next) -> - case f(elem, accumulator) { + case f(accumulator, elem) { list.Continue(accumulator) -> do_fold_until(next, f, accumulator) list.Stop(accumulator) -> accumulator } @@ -1073,7 +1066,7 @@ fn do_fold_until( pub fn fold_until( over iterator: Iterator(e), from initial: acc, - with f: fn(e, acc) -> list.ContinueOrStop(acc), + with f: fn(acc, e) -> list.ContinueOrStop(acc), ) -> acc { iterator.continuation |> do_fold_until(f, initial) @@ -1081,13 +1074,13 @@ pub fn fold_until( fn do_try_fold( over continuation: fn() -> Action(a), - with f: fn(a, acc) -> Result(acc, err), + with f: fn(acc, a) -> Result(acc, err), from accumulator: acc, ) -> Result(acc, err) { case continuation() { Stop -> Ok(accumulator) Continue(elem, next) -> { - try accumulator = f(elem, accumulator) + try accumulator = f(accumulator, elem) do_try_fold(next, f, accumulator) } } @@ -1115,7 +1108,7 @@ fn do_try_fold( pub fn try_fold( over iterator: Iterator(e), from initial: acc, - with f: fn(e, acc) -> Result(acc, err), + with f: fn(acc, e) -> Result(acc, err), ) -> Result(acc, err) { iterator.continuation |> do_try_fold(f, initial) diff --git a/src/gleam/list.gleam b/src/gleam/list.gleam index 283bb3f..a019653 100644 --- a/src/gleam/list.gleam +++ b/src/gleam/list.gleam @@ -296,19 +296,19 @@ pub fn map(list: List(a), with fun: fn(a) -> b) -> List(b) { /// pub fn map_fold( over list: List(a), - from memo: memo, - with fun: fn(a, memo) -> #(b, memo), -) -> #(List(b), memo) { + from acc: acc, + with fun: fn(acc, a) -> #(acc, b), +) -> #(acc, List(b)) { fold( over: list, - from: #([], memo), - with: fn(item, acc) { - let #(items, current_memo) = acc - let #(next_item, next_memo) = fun(item, current_memo) - #([next_item, ..items], next_memo) + from: #(acc, []), + with: fn(acc, item) { + let #(current_acc, items) = acc + let #(next_acc, next_item) = fun(current_acc, item) + #(next_acc, [next_item, ..items]) }, ) - |> pair.map_first(reverse) + |> pair.map_second(reverse) } fn do_index_map( @@ -530,10 +530,14 @@ pub fn flat_map(over list: List(a), with fun: fn(a) -> List(b)) -> List(b) { /// /// This function runs in linear time. /// -pub fn fold(over list: List(a), from initial: b, with fun: fn(a, b) -> b) -> b { +pub fn fold( + over list: List(a), + from initial: acc, + with fun: fn(acc, a) -> acc, +) -> acc { case list { [] -> initial - [x, ..rest] -> fold(rest, fun(x, initial), fun) + [x, ..rest] -> fold(rest, fun(initial, x), fun) } } @@ -550,25 +554,25 @@ pub fn fold(over list: List(a), from initial: b, with fun: fn(a, b) -> b) -> b { /// pub fn fold_right( over list: List(a), - from initial: b, - with fun: fn(a, b) -> b, -) -> b { + from initial: acc, + with fun: fn(acc, a) -> acc, +) -> acc { case list { [] -> initial - [x, ..rest] -> fun(x, fold_right(rest, initial, fun)) + [x, ..rest] -> fun(fold_right(rest, initial, fun), x) } } fn do_index_fold( over: List(a), - acc: b, - with: fn(Int, a, b) -> b, + acc: acc, + with: fn(acc, a, Int) -> acc, index: Int, -) -> b { +) -> acc { case over { [] -> acc [first, ..rest] -> - do_index_fold(rest, with(index, first, acc), with, index + 1) + do_index_fold(rest, with(acc, first, index), with, index + 1) } } @@ -583,9 +587,9 @@ fn do_index_fold( /// pub fn index_fold( over over: List(a), - from initial: b, - with fun: fn(Int, a, b) -> b, -) -> b { + from initial: acc, + with fun: fn(acc, a, Int) -> acc, +) -> acc { do_index_fold(over, initial, fun, 0) } @@ -609,13 +613,13 @@ pub fn index_fold( /// pub fn try_fold( over collection: List(a), - from accumulator: b, - with fun: fn(a, b) -> Result(b, e), -) -> Result(b, e) { + from accumulator: acc, + with fun: fn(acc, a) -> Result(acc, e), +) -> Result(acc, e) { case collection { [] -> Ok(accumulator) [first, ..rest] -> { - try accumulator = fun(first, accumulator) + try accumulator = fun(accumulator, first) try_fold(rest, accumulator, fun) } } @@ -646,13 +650,13 @@ pub type ContinueOrStop(a) { /// pub fn fold_until( over collection: List(a), - from accumulator: b, - with fun: fn(a, b) -> ContinueOrStop(b), -) -> b { + from accumulator: acc, + with fun: fn(acc, a) -> ContinueOrStop(acc), +) -> acc { case collection { [] -> accumulator [first, ..rest] -> - case fun(first, accumulator) { + case fun(accumulator, first) { Continue(next_accumulator) -> fold_until(rest, next_accumulator, fun) Stop(b) -> b } @@ -1479,14 +1483,14 @@ pub fn reduce(over list: List(a), with fun: fn(a, a) -> a) -> Result(a, Nil) { fn do_scan( list: List(a), - accumulator: b, - accumulated: List(b), - fun: fn(a, b) -> b, -) -> List(b) { + accumulator: acc, + accumulated: List(acc), + fun: fn(acc, a) -> acc, +) -> List(acc) { case list { [] -> reverse(accumulated) [x, ..xs] -> { - let next = fun(x, accumulator) + let next = fun(accumulator, x) do_scan(xs, next, [next, ..accumulated], fun) } } @@ -1501,9 +1505,9 @@ fn do_scan( /// pub fn scan( over list: List(a), - from initial: b, - with fun: fn(a, b) -> b, -) -> List(b) { + from initial: acc, + with fun: fn(acc, a) -> acc, +) -> List(acc) { do_scan(list, initial, [], fun) } @@ -1525,7 +1529,7 @@ pub fn scan( /// pub fn last(list: List(a)) -> Result(a, Nil) { list - |> reduce(fn(elem, _) { elem }) + |> reduce(fn(_, elem) { elem }) } /// Return unique combinations of elements in the list @@ -1553,7 +1557,7 @@ pub fn combinations(items: List(a), by n: Int) -> List(List(a)) { fold( first_combinations, combinations(xs, n), - fn(c, acc) { [c, ..acc] }, + fn(acc, c) { [c, ..acc] }, ) } } diff --git a/src/gleam/map.gleam b/src/gleam/map.gleam index 89efee4..24c5d29 100644 --- a/src/gleam/map.gleam +++ b/src/gleam/map.gleam @@ -209,13 +209,9 @@ if erlang { if javascript { fn do_map_values(f: fn(key, value) -> b, map: Map(key, value)) -> Map(key, b) { - let insert = fn(pair, map) { - let #(k, v) = pair - insert(map, k, f(k, v)) - } + let f = fn(map, k, v) { insert(map, k, f(k, v)) } map - |> to_list - |> list.fold(new(), insert) + |> fold(from: new(), with: f) } } @@ -305,16 +301,14 @@ if javascript { f: fn(key, value) -> Bool, map: Map(key, value), ) -> Map(key, value) { - let insert = fn(pair, map) { - let #(k, v) = pair + let insert = fn(map, k, v) { case f(k, v) { True -> insert(map, k, v) _ -> map } } map - |> to_list - |> list.fold(new(), insert) + |> fold(from: new(), with: insert) } } @@ -342,13 +336,13 @@ if erlang { if javascript { fn do_take(desired_keys: List(k), map: Map(k, v)) -> Map(k, v) { - let insert = fn(key, taken) { + let insert = fn(taken, key) { case get(map, key) { Ok(value) -> insert(taken, key, value) _ -> taken } } - list.fold(desired_keys, new(), insert) + list.fold(over: desired_keys, from: new(), with: insert) } } @@ -374,7 +368,7 @@ if erlang { } if javascript { - fn insert_pair(pair: #(k, v), map: Map(k, v)) -> Map(k, v) { + fn insert_pair(map: Map(k, v), pair: #(k, v)) -> Map(k, v) { insert(map, pair.0, pair.1) } @@ -425,7 +419,7 @@ if javascript { /// from_list([]) /// pub fn drop(from map: Map(k, v), drop disallowed_keys: List(k)) -> Map(k, v) { - list.fold(disallowed_keys, map, fn(key, acc) { delete(acc, key) }) + list.fold(over: disallowed_keys, from: map, with: delete) } /// Creates a new map with one entry updated using a given function. @@ -461,10 +455,10 @@ pub fn update( |> insert(map, key, _) } -fn do_fold(list: List(#(k, v)), initial: acc, fun: fn(k, v, acc) -> acc) -> acc { +fn do_fold(list: List(#(k, v)), initial: acc, fun: fn(acc, k, v) -> acc) -> acc { case list { [] -> initial - [#(k, v), ..tail] -> do_fold(tail, fun(k, v, initial), fun) + [#(k, v), ..tail] -> do_fold(tail, fun(initial, k, v), fun) } } @@ -488,7 +482,7 @@ fn do_fold(list: List(#(k, v)), initial: acc, fun: fn(k, v, acc) -> acc) -> acc pub fn fold( over map: Map(k, v), from initial: acc, - with fun: fn(k, v, acc) -> acc, + with fun: fn(acc, k, v) -> acc, ) -> acc { map |> to_list diff --git a/src/gleam/option.gleam b/src/gleam/option.gleam index d8338a2..2baeaed 100644 --- a/src/gleam/option.gleam +++ b/src/gleam/option.gleam @@ -29,7 +29,7 @@ pub fn all(list: List(Option(a))) -> Option(List(a)) { list.fold_right( list, from: Some([]), - with: fn(item, acc) { + with: fn(acc, item) { case acc, item { Some(values), Some(value) -> Some([value, ..values]) _, _ -> None diff --git a/src/gleam/set.gleam b/src/gleam/set.gleam index 67b2252..492ed81 100644 --- a/src/gleam/set.gleam +++ b/src/gleam/set.gleam @@ -122,7 +122,7 @@ pub fn from_list(members: List(member)) -> Set(member) { list.fold( over: members, from: map.new(), - with: fn(k, m) { map.insert(m, k, token) }, + with: fn(m, k) { map.insert(m, k, token) }, ) Set(map) } @@ -143,9 +143,9 @@ pub fn from_list(members: List(member)) -> Set(member) { pub fn fold( over set: Set(member), from initial: acc, - with reducer: fn(member, acc) -> acc, + with reducer: fn(acc, member) -> acc, ) -> acc { - map.fold(over: set.map, from: initial, with: fn(k, _, a) { reducer(k, a) }) + map.fold(over: set.map, from: initial, with: fn(a, k, _) { reducer(a, k) }) } /// Creates a new set from an existing set, minus any members that a given @@ -200,7 +200,7 @@ fn order(first: Set(member), second: Set(member)) -> #(Set(member), Set(member)) /// pub fn union(of first: Set(member), and second: Set(member)) -> Set(member) { let #(larger, smaller) = order(first, second) - fold(over: smaller, from: larger, with: fn(m, a) { insert(a, m) }) + fold(over: smaller, from: larger, with: insert) } /// Creates a new set that contains members that are present in both given sets. diff --git a/test/gleam/iterator_test.gleam b/test/gleam/iterator_test.gleam index 84292e4..2debc51 100644 --- a/test/gleam/iterator_test.gleam +++ b/test/gleam/iterator_test.gleam @@ -1,10 +1,7 @@ import gleam/should import gleam/iterator.{Done, Next} import gleam/list - -if erlang { - import gleam/map -} +import gleam/map // a |> from_list |> to_list == a pub fn to_from_list_test() { @@ -81,7 +78,7 @@ pub fn fold_test() { |> should.equal(list.fold(subject, acc, f)) } - let f = fn(e, acc) { [e, ..acc] } + let f = fn(acc, e) { [e, ..acc] } test([], [], f) test([1], [], f) test([1, 2, 3], [], f) @@ -372,22 +369,20 @@ pub fn all_test() { |> should.be_false } -if erlang { - pub fn group_test() { - iterator.from_list([1, 2, 3, 4, 5, 6]) - |> iterator.group(by: fn(n) { n % 3 }) - |> should.equal(map.from_list([#(0, [3, 6]), #(1, [1, 4]), #(2, [2, 5])])) - } +pub fn group_test() { + iterator.from_list([1, 2, 3, 4, 5, 6]) + |> iterator.group(by: fn(n) { n % 3 }) + |> should.equal(map.from_list([#(0, [3, 6]), #(1, [1, 4]), #(2, [2, 5])])) +} - pub fn reduce_test() { - iterator.empty() - |> iterator.reduce(with: fn(x, y) { x + y }) - |> should.equal(Error(Nil)) +pub fn reduce_test() { + iterator.empty() + |> iterator.reduce(with: fn(x, y) { x + y }) + |> should.equal(Error(Nil)) - iterator.from_list([1, 2, 3, 4, 5]) - |> iterator.reduce(with: fn(x, y) { x + y }) - |> should.equal(Ok(15)) - } + iterator.from_list([1, 2, 3, 4, 5]) + |> iterator.reduce(with: fn(x, y) { x + y }) + |> should.equal(Ok(15)) } pub fn last_test() { @@ -439,7 +434,7 @@ pub fn fold_until_test() { |> should.equal(list.fold_until(subject, acc, f)) } - let f = fn(e, acc) { + let f = fn(acc, e) { case e { _ if e < 6 -> list.Continue([e, ..acc]) _ -> list.Stop(acc) diff --git a/test/gleam/list_test.gleam b/test/gleam/list_test.gleam index 62a99aa..b0d81c3 100644 --- a/test/gleam/list_test.gleam +++ b/test/gleam/list_test.gleam @@ -108,8 +108,8 @@ pub fn map_test() { pub fn map_fold_test() { [1, 2, 3, 4] - |> list.map_fold(from: 0, with: fn(i, acc) { #(i * 2, acc + i) }) - |> should.equal(#([2, 4, 6, 8], 10)) + |> list.map_fold(from: 0, with: fn(acc, i) { #(acc + i, i * 2) }) + |> should.equal(#(10, [2, 4, 6, 8])) } pub fn try_map_test() { @@ -200,19 +200,19 @@ pub fn flat_map_test() { pub fn fold_test() { [1, 2, 3] - |> list.fold([], fn(x, acc) { [x, ..acc] }) + |> list.fold([], fn(acc, x) { [x, ..acc] }) |> should.equal([3, 2, 1]) } pub fn fold_right_test() { [1, 2, 3] - |> list.fold_right(from: [], with: fn(x, acc) { [x, ..acc] }) + |> list.fold_right(from: [], with: fn(acc, x) { [x, ..acc] }) |> should.equal([1, 2, 3]) } pub fn index_fold_test() { ["a", "b", "c"] - |> list.index_fold([], fn(ix, i, acc) { [#(ix, i), ..acc] }) + |> list.index_fold([], fn(acc, i, ix) { [#(ix, i), ..acc] }) |> should.equal([#(2, "c"), #(1, "b"), #(0, "a")]) } @@ -220,7 +220,7 @@ pub fn fold_until_test() { [1, 2, 3, 4] |> list.fold_until( from: 0, - with: fn(n, acc) { + with: fn(acc, n) { case n < 4 { True -> list.Continue(acc + n) False -> list.Stop(acc) @@ -672,17 +672,17 @@ pub fn reduce_test() { pub fn scan_test() { [] - |> list.scan(from: 0, with: fn(i, acc) { i + acc }) + |> list.scan(from: 0, with: fn(acc, i) { i + acc }) |> should.equal([]) [1, 2, 3, 4] - |> list.scan(from: 0, with: fn(i, acc) { 2 * i + acc }) + |> list.scan(from: 0, with: fn(acc, i) { 2 * i + acc }) |> should.equal([2, 6, 12, 20]) [1, 2, 3, 4] |> list.scan( from: [], - with: fn(i, acc) { + with: fn(acc, i) { case int.is_even(i) { True -> ["Even", ..acc] False -> ["Odd", ..acc] diff --git a/test/gleam/map_test.gleam b/test/gleam/map_test.gleam index fc90b93..95ed66b 100644 --- a/test/gleam/map_test.gleam +++ b/test/gleam/map_test.gleam @@ -162,13 +162,13 @@ pub fn update_test() { pub fn fold_test() { let dict = map.from_list([#("a", 0), #("b", 1), #("c", 2), #("d", 3)]) - let add = fn(_, v, acc) { v + acc } + let add = fn(acc, _, v) { v + acc } dict |> map.fold(0, add) |> should.equal(6) - let concat = fn(k, _, acc) { string.append(acc, k) } + let concat = fn(acc, k, _) { string.append(acc, k) } dict |> map.fold("", concat) |