aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRJ Dellecese <rjdellecese@gmail.com>2019-12-28 21:29:11 -0500
committerLouis Pilfold <louis@lpil.uk>2019-12-30 22:36:04 +0000
commit9292225d996c2092647fae15726a9f9bb2a691c8 (patch)
tree3e2b4edfcbe34c54eb279cd59924e9fc0ce13590
parenta37c8fcf7b8ed522bc7c23dc25c3a804f7728adb (diff)
downloadgleam_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.erl16
-rw-r--r--gen/test/gleam@generic_test.erl44
-rw-r--r--src/gleam/generic.gleam17
-rw-r--r--test/gleam/generic_test.gleam66
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")
+}