From 2b84f0f138c485582277435cae4625d3dec9c222 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Fernandes?= Date: Fri, 2 Aug 2024 23:33:13 -0300 Subject: [PATCH] [gleam] complete list-ops --- gleam/list-ops/.gitignore | 4 + gleam/list-ops/HELP.md | 32 +++++++ gleam/list-ops/README.md | 30 ++++++ gleam/list-ops/gleam.toml | 12 +++ gleam/list-ops/manifest.toml | 28 ++++++ gleam/list-ops/src/list_ops.gleam | 39 ++++++++ gleam/list-ops/test/list_ops_test.gleam | 121 ++++++++++++++++++++++++ 7 files changed, 266 insertions(+) create mode 100644 gleam/list-ops/.gitignore create mode 100644 gleam/list-ops/HELP.md create mode 100644 gleam/list-ops/README.md create mode 100644 gleam/list-ops/gleam.toml create mode 100644 gleam/list-ops/manifest.toml create mode 100644 gleam/list-ops/src/list_ops.gleam create mode 100644 gleam/list-ops/test/list_ops_test.gleam diff --git a/gleam/list-ops/.gitignore b/gleam/list-ops/.gitignore new file mode 100644 index 0000000..170cca9 --- /dev/null +++ b/gleam/list-ops/.gitignore @@ -0,0 +1,4 @@ +*.beam +*.ez +build +erl_crash.dump diff --git a/gleam/list-ops/HELP.md b/gleam/list-ops/HELP.md new file mode 100644 index 0000000..6cd5ae9 --- /dev/null +++ b/gleam/list-ops/HELP.md @@ -0,0 +1,32 @@ +# Help + +## Running the tests + +To run the tests, run the command `gleam test` from within the exercise directory. + +## Submitting your solution + +You can submit your solution using the `exercism submit src/list_ops.gleam` command. +This command will upload your solution to the Exercism website and print the solution page's URL. + +It's possible to submit an incomplete solution which allows you to: + +- See how others have completed the exercise +- Request help from a mentor + +## Need to get help? + +If you'd like help solving the exercise, check the following pages: + +- The [Gleam track's documentation](https://exercism.org/docs/tracks/gleam) +- The [Gleam track's programming category on the forum](https://forum.exercism.org/c/programming/gleam) +- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5) +- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs) + +Should those resources not suffice, you could submit your (incomplete) solution to request mentoring. + +To get help if you're having trouble, you can use one of the following resources: + +- [gleam.run](https://gleam.run/documentation/) is the gleam official documentation. +- [Discord](https://discord.gg/Fm8Pwmy) is the discord channel. +- [StackOverflow](https://stackoverflow.com/questions/tagged/gleam) can be used to search for your problem and see if it has been answered already. You can also ask and answer questions. \ No newline at end of file diff --git a/gleam/list-ops/README.md b/gleam/list-ops/README.md new file mode 100644 index 0000000..3d6986f --- /dev/null +++ b/gleam/list-ops/README.md @@ -0,0 +1,30 @@ +# List Ops + +Welcome to List Ops on Exercism's Gleam Track. +If you need help running the tests or submitting your code, check out `HELP.md`. + +## 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. + +## Source + +### Created by + +- @jiegillet \ No newline at end of file diff --git a/gleam/list-ops/gleam.toml b/gleam/list-ops/gleam.toml new file mode 100644 index 0000000..24a6712 --- /dev/null +++ b/gleam/list-ops/gleam.toml @@ -0,0 +1,12 @@ +name = "list_ops" +version = "0.1.0" + +[dependencies] +gleam_bitwise = "~> 1.2" +gleam_otp = "~> 0.7 or ~> 1.0" +gleam_stdlib = "~> 0.32 or ~> 1.0" +simplifile = "~> 1.0" +gleam_erlang = ">= 0.25.0 and < 1.0.0" + +[dev-dependencies] +exercism_test_runner = "~> 1.4" diff --git a/gleam/list-ops/manifest.toml b/gleam/list-ops/manifest.toml new file mode 100644 index 0000000..cb4e34e --- /dev/null +++ b/gleam/list-ops/manifest.toml @@ -0,0 +1,28 @@ +# This file was generated by Gleam +# You typically do not need to edit this file + +packages = [ + { name = "argv", version = "1.0.2", build_tools = ["gleam"], requirements = [], otp_app = "argv", source = "hex", outer_checksum = "BA1FF0929525DEBA1CE67256E5ADF77A7CDDFE729E3E3F57A5BDCAA031DED09D" }, + { name = "exercism_test_runner", version = "1.8.0", build_tools = ["gleam"], requirements = ["argv", "gap", "glance", "gleam_community_ansi", "gleam_erlang", "gleam_json", "gleam_stdlib", "simplifile"], otp_app = "exercism_test_runner", source = "hex", outer_checksum = "B944D89A9D049897DF28C63D595D89CB54D8C407D06EFFCE4CDA8C3EC1C9F51E" }, + { name = "filepath", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "filepath", source = "hex", outer_checksum = "EFB6FF65C98B2A16378ABC3EE2B14124168C0CE5201553DE652E2644DCFDB594" }, + { name = "gap", version = "1.1.3", build_tools = ["gleam"], requirements = ["gleam_community_ansi", "gleam_stdlib"], otp_app = "gap", source = "hex", outer_checksum = "6EF5E3B523FDFBC317E9EA28D5163EE04744A97C007106F90207569789612291" }, + { name = "glance", version = "0.11.0", build_tools = ["gleam"], requirements = ["gleam_stdlib", "glexer"], otp_app = "glance", source = "hex", outer_checksum = "8F3314D27773B7C3B9FB58D8C02C634290422CE531988C0394FA0DF8676B964D" }, + { name = "gleam_bitwise", version = "1.3.1", build_tools = ["gleam"], requirements = [], otp_app = "gleam_bitwise", source = "hex", outer_checksum = "B36E1D3188D7F594C7FD4F43D0D2CE17561DE896202017548578B16FE1FE9EFC" }, + { name = "gleam_community_ansi", version = "1.4.0", build_tools = ["gleam"], requirements = ["gleam_community_colour", "gleam_stdlib"], otp_app = "gleam_community_ansi", source = "hex", outer_checksum = "FE79E08BF97009729259B6357EC058315B6FBB916FAD1C2FF9355115FEB0D3A4" }, + { name = "gleam_community_colour", version = "1.4.0", build_tools = ["gleam"], requirements = ["gleam_json", "gleam_stdlib"], otp_app = "gleam_community_colour", source = "hex", outer_checksum = "795964217EBEDB3DA656F5EB8F67D7AD22872EB95182042D3E7AFEF32D3FD2FE" }, + { name = "gleam_erlang", version = "0.25.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_erlang", source = "hex", outer_checksum = "054D571A7092D2A9727B3E5D183B7507DAB0DA41556EC9133606F09C15497373" }, + { name = "gleam_json", version = "1.0.1", build_tools = ["gleam"], requirements = ["gleam_stdlib", "thoas"], otp_app = "gleam_json", source = "hex", outer_checksum = "9063D14D25406326C0255BDA0021541E797D8A7A12573D849462CAFED459F6EB" }, + { name = "gleam_otp", version = "0.10.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_stdlib"], otp_app = "gleam_otp", source = "hex", outer_checksum = "0B04FE915ACECE539B317F9652CAADBBC0F000184D586AAAF2D94C100945D72B" }, + { name = "gleam_stdlib", version = "0.39.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "2D7DE885A6EA7F1D5015D1698920C9BAF7241102836CE0C3837A4F160128A9C4" }, + { name = "glexer", version = "1.0.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "glexer", source = "hex", outer_checksum = "BD477AD657C2B637FEF75F2405FAEFFA533F277A74EF1A5E17B55B1178C228FB" }, + { name = "simplifile", version = "1.7.0", build_tools = ["gleam"], requirements = ["filepath", "gleam_stdlib"], otp_app = "simplifile", source = "hex", outer_checksum = "1D5DFA3A2F9319EC85825F6ED88B8E449F381B0D55A62F5E61424E748E7DDEB0" }, + { name = "thoas", version = "1.2.1", build_tools = ["rebar3"], requirements = [], otp_app = "thoas", source = "hex", outer_checksum = "E38697EDFFD6E91BD12CEA41B155115282630075C2A727E7A6B2947F5408B86A" }, +] + +[requirements] +exercism_test_runner = { version = "~> 1.4" } +gleam_bitwise = { version = "~> 1.2" } +gleam_erlang = { version = ">= 0.25.0 and < 1.0.0" } +gleam_otp = { version = "~> 0.7 or ~> 1.0" } +gleam_stdlib = { version = "~> 0.32 or ~> 1.0" } +simplifile = { version = "~> 1.0" } diff --git a/gleam/list-ops/src/list_ops.gleam b/gleam/list-ops/src/list_ops.gleam new file mode 100644 index 0000000..dd91008 --- /dev/null +++ b/gleam/list-ops/src/list_ops.gleam @@ -0,0 +1,39 @@ +pub fn append(first first: List(a), second second: List(a)) -> List(a) { + foldr(first, second, fn(acc, a) { [a, ..acc] }) +} + +pub fn concat(lists: List(List(a))) -> List(a) { + foldl(lists, [], append) +} + +pub fn filter(list: List(a), f: fn(a) -> Bool) -> List(a) { + foldr(list, [], fn(acc, a) { + case f(a) { + True -> [a, ..acc] + False -> acc + } + }) +} + +pub fn length(list: List(a)) -> Int { + foldl(list, 0, fn(acc, _) { acc + 1 }) +} + +pub fn map(list: List(a), f: fn(a) -> b) -> List(b) { + foldr(list, [], fn(acc, a) { [f(a), ..acc] }) +} + +pub fn foldl(over list: List(a), from acc: b, with f: fn(b, a) -> b) -> b { + case list { + [] -> acc + [head, ..tail] -> foldl(tail, f(acc, head), f) + } +} + +pub fn foldr(over list: List(a), from acc: b, with f: fn(b, a) -> b) -> b { + foldl(reverse(list), acc, f) +} + +pub fn reverse(list: List(a)) -> List(a) { + foldl(list, [], fn(acc, a) { [a, ..acc] }) +} diff --git a/gleam/list-ops/test/list_ops_test.gleam b/gleam/list-ops/test/list_ops_test.gleam new file mode 100644 index 0000000..9654f64 --- /dev/null +++ b/gleam/list-ops/test/list_ops_test.gleam @@ -0,0 +1,121 @@ +import exercism/should +import exercism/test_runner +import list_ops + +pub fn main() { + test_runner.main() +} + +pub fn append_entries_to_a_list_and_return_the_new_list_empty_lists_test() { + list_ops.append(first: [], second: []) + |> should.equal([]) +} + +pub fn append_entries_to_a_list_and_return_the_new_list_list_to_empty_list_test() { + list_ops.append(first: [], second: [1, 2, 3, 4]) + |> should.equal([1, 2, 3, 4]) +} + +pub fn append_entries_to_a_list_and_return_the_new_list_empty_list_to_list_test() { + list_ops.append(first: [1, 2, 3, 4], second: []) + |> should.equal([1, 2, 3, 4]) +} + +pub fn append_entries_to_a_list_and_return_the_new_list_non_empty_lists_test() { + list_ops.append(first: [1, 2], second: [2, 3, 4, 5]) + |> should.equal([1, 2, 2, 3, 4, 5]) +} + +pub fn concatenate_a_list_of_lists_empty_list_test() { + list_ops.concat([]) + |> should.equal([]) +} + +pub fn concatenate_a_list_of_lists_list_of_lists_test() { + list_ops.concat([[1, 2], [3], [], [4, 5, 6]]) + |> should.equal([1, 2, 3, 4, 5, 6]) +} + +pub fn concatenate_a_list_of_lists_list_of_nested_lists_test() { + list_ops.concat([[[1], [2]], [[3]], [[]], [[4, 5, 6]]]) + |> should.equal([[1], [2], [3], [], [4, 5, 6]]) +} + +pub fn filter_list_returning_only_values_that_satisfy_the_filter_function_empty_list_test() { + list_ops.filter([], fn(x) { x % 2 == 1 }) + |> should.equal([]) +} + +pub fn filter_list_returning_only_values_that_satisfy_the_filter_function_non_empty_list_test() { + list_ops.filter([1, 2, 3, 5], fn(x) { x % 2 == 1 }) + |> should.equal([1, 3, 5]) +} + +pub fn returns_the_length_of_a_list_empty_list_test() { + list_ops.length([]) + |> should.equal(0) +} + +pub fn returns_the_length_of_a_list_non_empty_list_test() { + list_ops.length([1, 2, 3, 4]) + |> should.equal(4) +} + +pub fn return_a_list_of_elements_whose_values_equal_the_list_value_transformed_by_the_mapping_function_empty_list_test() { + list_ops.map([], fn(x) { x + 1 }) + |> should.equal([]) +} + +pub fn return_a_list_of_elements_whose_values_equal_the_list_value_transformed_by_the_mapping_function_non_empty_list_test() { + list_ops.map([1, 3, 5, 7], fn(x) { x + 1 }) + |> should.equal([2, 4, 6, 8]) +} + +pub fn folds_reduces_the_given_list_from_the_left_with_a_function_empty_list_test() { + list_ops.foldl(with: fn(acc, el) { el * acc }, from: 2, over: []) + |> should.equal(2) +} + +pub fn folds_reduces_the_given_list_from_the_left_with_a_function_direction_independent_function_applied_to_non_empty_list_test() { + list_ops.foldl(with: fn(acc, el) { el + acc }, from: 5, over: [1, 2, 3, 4]) + |> should.equal(15) +} + +pub fn folds_reduces_the_given_list_from_the_left_with_a_function_direction_dependent_function_applied_to_non_empty_list_test() { + list_ops.foldl(with: fn(acc, el) { el /. acc }, from: 24.0, over: [ + 1.0, 2.0, 3.0, 4.0, + ]) + |> should.equal(64.0) +} + +pub fn folds_reduces_the_given_list_from_the_right_with_a_function_empty_list_test() { + list_ops.foldr(with: fn(acc, el) { el * acc }, from: 2, over: []) + |> should.equal(2) +} + +pub fn folds_reduces_the_given_list_from_the_right_with_a_function_direction_independent_function_applied_to_non_empty_list_test() { + list_ops.foldr(with: fn(acc, el) { el + acc }, from: 5, over: [1, 2, 3, 4]) + |> should.equal(15) +} + +pub fn folds_reduces_the_given_list_from_the_right_with_a_function_direction_dependent_function_applied_to_non_empty_list_test() { + list_ops.foldr(with: fn(acc, el) { el /. acc }, from: 24.0, over: [ + 1.0, 2.0, 3.0, 4.0, + ]) + |> should.equal(9.0) +} + +pub fn reverse_the_elements_of_the_list_empty_list_test() { + list_ops.reverse([]) + |> should.equal([]) +} + +pub fn reverse_the_elements_of_the_list_non_empty_list_test() { + list_ops.reverse([1, 3, 5, 7]) + |> should.equal([7, 5, 3, 1]) +} + +pub fn reverse_the_elements_of_the_list_list_of_lists_is_not_flattened_test() { + list_ops.reverse([[1, 2], [3], [], [4, 5, 6]]) + |> should.equal([[4, 5, 6], [], [3], [1, 2]]) +}