| 1 | -module(hope_list). |
| 2 | |
| 3 | -export_type( |
| 4 | [ t/1 |
| 5 | ]). |
| 6 | |
| 7 | -export( |
| 8 | [ unique_preserve_order/1 |
| 9 | , map_rev/2 |
| 10 | , map_slow/2 |
| 11 | ]). |
| 12 | |
| 13 | |
| 14 | -type t(A) :: |
| 15 | [A]. |
| 16 | |
| 17 | |
| 18 | %% @doc lists:reverse(map_rev(L, F)) |
| 19 | %% @end |
| 20 | -spec map_slow([A], fun((A) -> (B))) -> |
| 21 | [B]. |
| 22 | map_slow(Xs, F) -> |
| 23 | lists:reverse(map_rev(Xs, F)). |
| 24 | |
| 25 | |
| 26 | %% @doc Tail-recursive alternative to lists:map/2, which accumulates and |
| 27 | %% returns list in reverse order. |
| 28 | %% @end |
| 29 | -spec map_rev([A], fun((A) -> (B))) -> |
| 30 | [B]. |
| 31 | map_rev(Xs, F) -> |
| 32 | map_rev_acc(Xs, F, []). |
| 33 | |
| 34 | -spec map_rev_acc([A], fun((A) -> (B)), [B]) -> |
| 35 | [B]. |
| 36 | map_rev_acc([], _, Ys) -> |
| 37 | Ys; |
| 38 | map_rev_acc([X|Xs], F, Ys) -> |
| 39 | Y = F(X), |
| 40 | map_rev_acc(Xs, F, [Y|Ys]). |
| 41 | |
| 42 | |
| 43 | -spec unique_preserve_order(t(A)) -> |
| 44 | t(A). |
| 45 | unique_preserve_order(L) -> |
| 46 | PrependIfNew = |
| 47 | fun (X, Xs) -> |
| 48 | case lists:member(X, Xs) |
| 49 | of true -> Xs |
| 50 | ; false -> [X | Xs] |
| 51 | end |
| 52 | end, |
| 53 | lists:reverse(lists:foldl(PrependIfNew, [], L)). |