Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement list ops exercise #297

Merged
merged 2 commits into from
Oct 16, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions config.json
Original file line number Diff line number Diff line change
Expand Up @@ -689,6 +689,16 @@
"games",
"parsing"
]
},
{
"slug": "list-ops",
"uuid": "e80410bb-45e5-4007-ad97-e7470dd87ed5",
"core": false,
"unlocked_by": "rna-transcription",
"difficulty": 2,
"topics": [
"lists"
]
}
]
}
33 changes: 33 additions & 0 deletions exercises/list-ops/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# List Ops

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.

## Running tests

In order to run the tests, issue the following command from the exercise
directory:

For running the tests provided, `rebar3` is used as it is the official build and
dependency management tool for erlang now. Please refer to [the tracks installation
instructions](http://exercism.io/languages/erlang/installation) on how to do that.

In order to run the tests, you can issue the following command from the exercise
directory.

```bash
$ rebar3 eunit
```

## Questions?

For detailed information about the Erlang track, please refer to the
[help page](http://exercism.io/languages/erlang) on the Exercism site.
This covers the basic information on setting up the development
environment expected by the exercises.

## Submitting Incomplete Solutions
It's possible to submit an incomplete solution so you can see how others have completed the exercise.
30 changes: 30 additions & 0 deletions exercises/list-ops/rebar.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
%% Erlang compiler options
{erl_opts, [debug_info, warnings_as_errors]}.

{deps, [{erl_exercism, "0.1.2"}]}.

{dialyzer, [
{warnings, [underspecs, no_return]},
{get_warnings, true},
{plt_apps, top_level_deps}, % top_level_deps | all_deps
{plt_extra_apps, []},
{plt_location, local}, % local | "/my/file/name"
{plt_prefix, "rebar3"},
{base_plt_apps, [stdlib, kernel, crypto]},
{base_plt_location, global}, % global | "/my/file/name"
{base_plt_prefix, "rebar3"}
]}.

%% eunit:test(Tests)
{eunit_tests, []}.
%% Options for eunit:test(Tests, Opts)
{eunit_opts, [verbose]}.

%% == xref ==

{xref_warnings, true}.

%% xref checks to run
{xref_checks, [undefined_function_calls, undefined_functions,
locals_not_used, exports_not_used,
deprecated_function_calls, deprecated_functions]}.
54 changes: 54 additions & 0 deletions exercises/list-ops/src/example.erl
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
-module(example).

-export([append/2, concat/1, filter/2, length/1, map/2, foldl/3, foldr/3,
reverse/1]).

append(L1, L2) -> L1 ++ L2.

concat(L) ->
concat(reverse(L), []).

concat([], Acc) -> Acc;
concat([Curr|Rest], Acc) ->
concat(Rest, extract_sublist(reverse(Curr), Acc)).

extract_sublist([], Acc) -> Acc;
extract_sublist([Curr|Rest], Acc) -> extract_sublist(Rest, [Curr|Acc]).

filter(Fun, L) ->
filter(Fun, L, []).

filter(_, [], Acc) -> reverse(Acc);
filter(Fun, [Curr|Rest], Acc) ->
case Fun(Curr) of
true -> filter(Fun, Rest, [Curr|Acc]);
false -> filter(Fun, Rest, Acc)
end.

length(L) -> length(L, 0).

length([], Acc) -> Acc;
length([_|Rest], Acc) -> length(Rest, Acc + 1).

map(Fun, L) ->
map(Fun, L, []).

map(_, [], Acc) -> reverse(Acc);
map(Fun, [Curr|Rest], Acc) -> map(Fun, Rest, [Fun(Curr)|Acc]).

foldl(Fun, Start, L) -> reduce_foldl(Fun, L, Start).
reduce_foldl(_, [], Acc) -> Acc;
reduce_foldl(Fun, [Curr|Rest], Acc) ->
reduce_foldl(Fun, Rest, Fun(Acc, Curr)).

foldr(Fun, Start, L) -> reduce_foldr(Fun, reverse(L), Start).

reduce_foldr(_, [], Acc) -> Acc;
reduce_foldr(Fun, [Curr|Rest], Acc) ->
reduce_foldr(Fun, Rest, Fun(Curr, Acc)).

reverse(L) ->
reverse(L, []).

reverse([], Acc) -> Acc;
reverse([Curr|Rest], Acc) -> reverse(Rest, [Curr|Acc]).
9 changes: 9 additions & 0 deletions exercises/list-ops/src/list_ops.app.src
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{application, list_ops,
[{description, "exercism.io - list-ops"},
{vsn, "0.0.1"},
{modules, []},
{registered, []},
{applications, [kernel,
stdlib]},
{env, []}
]}.
20 changes: 20 additions & 0 deletions exercises/list-ops/src/list_ops.erl
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
-module(list_ops).

-export([append/2, concat/1, filter/2, length/1, map/2, foldl/3, foldr/3,
reverse/1]).

append(_List1, _List2) -> undefined.

concat(_List) -> undefined.

filter(_Function, _List) -> undefined.

length(_List) -> undefined.

map(_Function, _List) -> undefined.

foldl(_Function, _Start, _List) -> undefined.

foldr(_Function, _Start, _List) -> undefined.

reverse(_List) -> undefined.
87 changes: 87 additions & 0 deletions exercises/list-ops/test/list_ops_tests.erl
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
%% based on canonical data version 2.3.0
%% https://raw.githubusercontent.com/exercism/problem-specifications/master/exercises/list-ops/canonical-data.json

-module(list_ops_tests).

-include_lib("erl_exercism/include/exercism.hrl").
-include_lib("eunit/include/eunit.hrl").

append_empty_lists_test() ->
?assertEqual([],
list_ops:append([], [])).

append_empty_list_to_list_test() ->
?assertEqual([1,2,3,4],
list_ops:append([], [1,2,3,4])).

append_non_empty_lists_test() ->
?assertEqual([1,2,2,3,4,5],
list_ops:append([1,2], [2,3,4,5])).

concat_empty_list_test() ->
?assertEqual([],
list_ops:concat([])).

concat_list_of_lists_test() ->
?assertEqual([1,2,3,4,5,6],
list_ops:concat([[1,2], [3], [], [4,5,6]])).

concat_list_of_nested_lists_test() ->
?assertEqual([[1], [2], [3], [], [4,5,6]],
list_ops:concat([[[1], [2]], [[3]], [[]], [[4,5,6]]])).

filter_empty_list_test() ->
?assertEqual([],
list_ops:filter(fun(X) -> X rem 2 =:= 1 end, [])).

filter_non_empty_list_test() ->
?assertEqual([1,3,5],
list_ops:filter(fun(X) -> X rem 2 =:= 1 end, [1,2,3,5])).

length_empty_list_test() ->
?assertEqual(0,
list_ops:length([])).

length_non_empty_list_test() ->
?assertEqual(4,
list_ops:length([1,2,3,4])).

map_empty_list_test() ->
?assertEqual([],
list_ops:map(fun(X) -> X + 1 end, [])).

map_non_empty_list_test() ->
?assertEqual([2,4,6,8],
list_ops:map(fun(X) -> X + 1 end, [1,3,5,7])).

foldl_empty_list_test() ->
?assertEqual(2,
list_ops:foldl(fun(X,Y) -> X * Y end, 2, [])).

foldl_direction_independent_function_applied_to_non_empty_list_test() ->
?assertEqual(15,
list_ops:foldl(fun(X,Y) -> X + Y end, 5, [1,2,3,4])).

foldl_direction_dependent_function_applied_to_non_empty_list_test() ->
?assertEqual(0,
list_ops:foldl(fun(X,Y) -> X div Y end, 5, [2,5])).

foldr_empty_list_test() ->
?assertEqual(2,
list_ops:foldr(fun(X,Y) -> X * Y end, 2, [])).

foldr_direction_independent_function_applied_to_non_empty_list_test() ->
?assertEqual(15,
list_ops:foldr(fun(X,Y) -> X + Y end, 5, [1,2,3,4])).

foldr_direction_dependent_function_applied_to_non_empty_list_test() ->
?assertEqual(2,
list_ops:foldr(fun(X,Y) -> X div Y end, 5, [2,5])).

reverse_empty_list_test() ->
?assertEqual([],
list_ops:reverse([])).

reverse_non_empty_list_test() ->
?assertEqual([7,5,3,1],
list_ops:reverse([1,3,5,7])).