diff options
author | RJ Dellecese <rjdellecese@gmail.com> | 2019-12-28 21:29:11 -0500 |
---|---|---|
committer | Louis Pilfold <louis@lpil.uk> | 2019-12-30 22:36:04 +0000 |
commit | 9292225d996c2092647fae15726a9f9bb2a691c8 (patch) | |
tree | 3e2b4edfcbe34c54eb279cd59924e9fc0ce13590 | |
parent | a37c8fcf7b8ed522bc7c23dc25c3a804f7728adb (diff) | |
download | gleam_stdlib-9292225d996c2092647fae15726a9f9bb2a691c8.tar.gz gleam_stdlib-9292225d996c2092647fae15726a9f9bb2a691c8.zip |
Add generic module
Containing identity, always, flip, and compose functions.
-rw-r--r-- | gen/src/gleam@generic.erl | 16 | ||||
-rw-r--r-- | gen/test/gleam@generic_test.erl | 44 | ||||
-rw-r--r-- | src/gleam/generic.gleam | 17 | ||||
-rw-r--r-- | test/gleam/generic_test.gleam | 66 |
4 files changed, 143 insertions, 0 deletions
diff --git a/gen/src/gleam@generic.erl b/gen/src/gleam@generic.erl new file mode 100644 index 0000000..a25a59f --- /dev/null +++ b/gen/src/gleam@generic.erl @@ -0,0 +1,16 @@ +-module(gleam@generic). +-compile(no_auto_import). + +-export([identity/1, always/2, flip/1, compose/2]). + +identity(A) -> + A. + +always(_, B) -> + B. + +flip(Fun) -> + fun(B, A) -> Fun(A, B) end. + +compose(Fun1, Fun2) -> + fun(A) -> Fun2(Fun1(A)) end. diff --git a/gen/test/gleam@generic_test.erl b/gen/test/gleam@generic_test.erl new file mode 100644 index 0000000..eecf650 --- /dev/null +++ b/gen/test/gleam@generic_test.erl @@ -0,0 +1,44 @@ +-module(gleam@generic_test). +-compile(no_auto_import). + +-export([identity_test/0, always_test/0, flip_test/0, compose_test/0]). + +identity_test() -> + gleam@expect:equal(gleam@generic:identity(1), 1). + +always_test() -> + gleam@expect:equal(gleam@generic:always(1, 2), 2). + +flip_test() -> + Fun = fun(String, Int) -> + gleam@string:append( + gleam@string:append( + gleam@string:append( + gleam@string:append(<<"String: '">>, String), + <<"', Int: '">> + ), + gleam@int:to_string(Int) + ), + <<"'">> + ) + end, + FlippedFun = gleam@generic:flip(Fun), + gleam@expect:equal(Fun(<<"Bob">>, 1), <<"String: 'Bob', Int: '1'">>), + gleam@expect:equal( + FlippedFun(2, <<"Alice">>), + <<"String: 'Alice', Int: '2'">> + ). + +compose_test() -> + AddTwo = fun(Int) -> Int + 2 end, + AddThree = fun(Int1) -> Int1 + 3 end, + AddFive = gleam@generic:compose(AddTwo, AddThree), + gleam@expect:equal(AddFive(1), 6), + HeadToString = gleam@generic:compose( + fun gleam@list:head/1, + fun(IntResult) -> + gleam@int:to_string(gleam@result:unwrap(IntResult, 0)) + end + ), + gleam@expect:equal(HeadToString([1]), <<"1">>), + gleam@expect:equal(HeadToString([]), <<"0">>). diff --git a/src/gleam/generic.gleam b/src/gleam/generic.gleam new file mode 100644 index 0000000..d821ac7 --- /dev/null +++ b/src/gleam/generic.gleam @@ -0,0 +1,17 @@ +// A function that returns exactly what it was given. +pub fn identity(a: a) -> a { a } + +// A function that, given two values, ignores one and always returns the other. +pub fn always(_a: a, b: b) -> b { b } + +// Takes a function that takes two arguments and returns a new function that +// takes the same two arguments, but in reverse order. +pub fn flip(fun: fn(a, b) -> c) -> fn(b, a) -> c { + fn(b, a) { fun(a, b) } +} + +// Takes two functions and chains them together to form one function that takes +// the input from the first and returns the output of the second. +pub fn compose(fun1: fn(a) -> b, fun2: fn(b) -> c) -> fn(a) -> c { + fn(a) { fun1(a) |> fun2 } +} diff --git a/test/gleam/generic_test.gleam b/test/gleam/generic_test.gleam new file mode 100644 index 0000000..a65e931 --- /dev/null +++ b/test/gleam/generic_test.gleam @@ -0,0 +1,66 @@ +import gleam/expect +import gleam/generic.{identity, always, flip, compose} +import gleam/int as int_mod +import gleam/list +import gleam/result +import gleam/string as string_mod + +pub fn identity_test() { + 1 + |> identity + |> expect.equal(_, 1) +} + +pub fn always_test() { + 1 + |> always(_, 2) + |> expect.equal(_, 2) +} + +pub fn flip_test() { + let fun = fn(string: String, int: Int) { + string + |> string_mod.append("String: '", _) + |> string_mod.append(_, "', Int: '") + |> string_mod.append(_, int_mod.to_string(int)) + |> string_mod.append(_, "'") + } + + let flipped_fun = flip(fun) + + fun("Bob", 1) + |> expect.equal(_, "String: 'Bob', Int: '1'") + + flipped_fun(2, "Alice") + |> expect.equal(_, "String: 'Alice', Int: '2'") +} + +pub fn compose_test() { + let add_two = fn(int: Int) { int + 2 } + let add_three = fn(int: Int) { int + 3 } + + let add_five = compose(add_two, add_three) + + 1 + |> add_five + |> expect.equal(_, 6) + + // Takes a list of ints and returns the head as a string (if there is one, or + // else "0" if there is not) + let head_to_string = + compose( + list.head, + fn(int_result: Result(Int, Nil)) { + result.unwrap(int_result, 0) + |> int_mod.to_string + } + ) + + [1] + |> head_to_string + |> expect.equal(_, "1") + + [] + |> head_to_string + |> expect.equal(_, "0") +} |