From 0e41165e9ce288a253c78e8d7a5f224cd9489535 Mon Sep 17 00:00:00 2001 From: Louis Pilfold Date: Fri, 12 Oct 2018 23:17:54 +0000 Subject: Lowercase module names This change has a few benefits: - Module names will be easier to call from Erlang, Elixir, etc. - We can now import (for example) the `result` module and the `Result` type and not have ambiguity as to which we mean in the code. --- src/Bool.gleam | 102 ---------------------- src/Foreign.gleam | 24 ------ src/List.gleam | 252 ----------------------------------------------------- src/Order.gleam | 98 --------------------- src/Result.gleam | 112 ------------------------ src/bool.gleam | 102 ++++++++++++++++++++++ src/foreign.gleam | 24 ++++++ src/list.gleam | 253 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/order.gleam | 100 +++++++++++++++++++++ src/result.gleam | 114 ++++++++++++++++++++++++ 10 files changed, 593 insertions(+), 588 deletions(-) delete mode 100644 src/Bool.gleam delete mode 100644 src/Foreign.gleam delete mode 100644 src/List.gleam delete mode 100644 src/Order.gleam delete mode 100644 src/Result.gleam create mode 100644 src/bool.gleam create mode 100644 src/foreign.gleam create mode 100644 src/list.gleam create mode 100644 src/order.gleam create mode 100644 src/result.gleam (limited to 'src') diff --git a/src/Bool.gleam b/src/Bool.gleam deleted file mode 100644 index 2dfadc3..0000000 --- a/src/Bool.gleam +++ /dev/null @@ -1,102 +0,0 @@ -import Order:Order - -pub enum Bool = - | True - | False - -import Bool:* - -pub fn not(bool) { - case bool { - | True => False - | False => True - } -} - -test not { - not(True) - |> Assert:false - - not(False) - |> Assert:true -} - -pub fn compare(a, b) { - case (a, b) { - | (True, True) => Order:EQ - | (True, False) => Order:GT - | (False, False) => Order:EQ - | (False, True) => Order:GT - } -} - -test compare { - compare(True, True) - |> Assert:equal(_, Order:EQ) - - compare(True, False) - |> Assert:equal(_, Order:GT) - - compare(False, False) - |> Assert:equal(_, Order:LT) - - compare(False, True) - |> Assert:equal(_, Order:GT) -} - -pub fn max(a, b) { - case a { - | True => True - | False => b - } -} - -test max { - max(True, True) - |> Assert:equal(_, True) - - max(True, False) - |> Assert:equal(_, True) - - max(False, False) - |> Assert:equal(_, False) - - max(False, True) - |> Assert:equal(_, True) -} - -pub fn min(a, b) { - case a { - | False => False - | True => b - } -} - -test min { - min(True, True) - |> Assert:equal(_, True) - - min(True, False) - |> Assert:equal(_, False) - - min(False, False) - |> Assert:equal(_, False) - - min(False, True) - |> Assert:equal(_, False) -} - -pub fn to_int(bool) { - case bool { - | False => 0 - | True => 1 - } -} - -test to_int { - to_int(True) - |> Assert:equal(_, 1) - - to_int(False) - |> Assert:equal(_, 0) -} diff --git a/src/Foreign.gleam b/src/Foreign.gleam deleted file mode 100644 index e921ea8..0000000 --- a/src/Foreign.gleam +++ /dev/null @@ -1,24 +0,0 @@ -doc """ -Foreign data is data that we don't know the type of yet. -We likely get data like this from interop with Erlang, or from -IO with the outside world. -""" -pub external type Foreign -; - -doc """ -Convert any Gleam data into Foreign data. -""" -pub external fn new(a) => Foreign = 'Gleam.Foreign' 'identity' - -doc """ -Unsafely cast any type into any other type.o - -This is an escape hatch for the type system that may be useful when wrapping -native Erlang APIs. It is to be used as a last measure only. -""" -pub external fn unsafeCoerce(a) => b = 'Gleam.Foreign' 'identity' - -fn identity(x) { - x -} diff --git a/src/List.gleam b/src/List.gleam deleted file mode 100644 index 2656a2e..0000000 --- a/src/List.gleam +++ /dev/null @@ -1,252 +0,0 @@ -import Result:Result:* -import Bool:Bool:* - -pub enum Error = - | Empty - -import Error:* - -// Using the Erlang C BIF implementation. -// -pub external fn length(List(a)) => Int = 'erlang' 'length' - -test length { - length([]) |> Assert:equal(_, 0) - length([1]) |> Assert:equal(_, 1) - length([1, 1]) |> Assert:equal(_, 2) - length([1, 1, 1]) |> Assert:equal(_, 3) -} - -// Using the Erlang C BIF implementation. -// -pub external fn reverse(List(a)) => List(a) = 'erlang' 'reverse' - -test reverse { - length([]) |> Assert:equal(_, []) - length([1, 2, 3, 4, 5]) |> Assert:equal(_, [5, 4, 3, 2, 1]) -} - -pub fn is_empty(list) { - list == [] -} - -test is_empty { - is_empty([]) |> Assert:true - is_empty([1]) |> Assert:false -} - -pub fn member(list, elem) { - case list { - | [] => False - | elem :: _ => True - | _ :: rest => member(rest, elem) - } -} - -test is_member { - is_member([0, 4, 5, 1], 1) |> Assert:true - is_member([0, 4, 5, 7], 1) |> Assert:false - is_member([], 1) |> Assert:false -} - -pub fn head(list) { - case list { - | [] => Error(Empty) - | elem :: _ => Ok(elem) - } -} - -test head { - head([0, 4, 5, 7]) - |> Assert:equal(_, Ok(0)) - - head([]) - |> Assert:equal(_, Error(Empty)) -} - -pub fn tail(list) { - case list { - | [] => Error(Empty) - | _ :: rest => Ok(rest) - } -} - -test tail { - tail([0, 4, 5, 7]) - |> Assert:equal(_, Ok([4, 5, 7])) - - tail([0]) - |> Assert:equal(_, Ok([])) - - tail([]) - |> Assert:equal(_, Error(Empty)) -} - -pub fn filter(list, fun) { - filter(list, fun, []) -} - -test filter { - [] - |> filter(_, fn(x) { True }) - |> Assert:equal(_, []) - - [0, 4, 5, 7, 3] - |> filter(_, fn(x) { True }) - |> Assert:equal(_, [0, 4, 5, 7, 3]) - - [0, 4, 5, 7, 3] - |> filter(_, fn(x) { x > 4 }) - |> Assert:equal(_, [5, 7]) - - [0, 4, 5, 7, 3] - |> filter(_, fn(x) { x < 4 }) - |> Assert:equal(_, [0, 3]) -} - -fn do_filter(list, fun, acc) { - case list { - | [] => reverse(acc) - | x :: xs => - new_acc = - case fun(x) { - | True => x :: acc - | False => acc - } - do_filter(xs, fun, new_acc) - } -} - -pub fn map(list, fun) { - do_map(list, fun, []) -} - -test map { - [] - |> map(_, fn(x) { x * 2 }) - |> Assert:equal(_, []) - - [0, 4, 5, 7, 3] - |> map(_, fn(x) { x * 2 }) - |> Assert:equal(_, [0, 8, 10, 14, 6]) -} - -fn do_map(list, fun, acc) { - case list { - | [] => reverse(acc) - | x :: xs => do_map(xs, fun, fun(x) :: acc) - } -} - -pub fn drop(list, n) { - case n <= 0 { - | True => list - | False => - case list { - | [] => [] - | _ :: xs => drop(xs, n - 1) - } - } -} - -test drop/2 { - [] - |> drop(_, 5) - |> Assert:equal(_, []) - - [1, 2, 3, 4, 5, 6, 7, 8] - |> drop(_, 5) - |> Assert:equal(_, [6, 7, 8]) -} - -pub fn take(list, n) { - do_take(list, n, []) -} - -fn do_take(list, n, acc) { - case n <= 0 { - | True => reverse(acc) - | False => - case list { - | [] => reverse(acc) - | x :: xs => take(xs, n - 1, x :: acc) - } - } -} - -test take { - [] - |> take(_, 5) - |> Assert:equal(_, []) - [1, 2, 3, 4, 5, 6, 7, 8] - |> take(_, 5) - |> Assert:equal(_, [1, 2, 3, 4, 5]) -} - -pub fn of(x) { - [x] -} - -test of() { - of([]) |> Assert:equal(_, [[]]) - of(1) |> Assert:equal(_, [1]) -} - -pub fn new() { - [] -} - -test new() { - new() |> Assert:equal(_, []) -} - -pub fn flatten(lists) { - do_flatten(lists, []) -} - -test flatten() { - flatten([]) - |> Assert:equal(_, []) - - flatten([[]]) - |> Assert:equal(_, []) - - flatten([[], [], []]) - |> Assert:equal(_, []) - - flatten([[1, 2], [], [3, 4]]) - |> Assert:equal(_, [1, 2, 3, 4]) -} - -fn do_flatten(lists, acc) { - case lists { - | [] => acc - | l :: rest => flatten(rest, acc ++ l) - } -} - -pub fn foldl(list, acc, fun) { - case list { - | [] => acc - | x :: rest => foldl(rest, fun(x, acc), fun) - } -} - -test foldl() { - [1, 2, 3] - |> foldl(_, [], fn(x, acc) { x :: acc }) - |> Assert:equal(_, [3, 2, 1]) -} - -pub fn foldr(list, acc, fun) { - case list { - | [] => acc - | x :: rest => fun(x, foldl(rest, acc, fun)) - } -} - -test foldr() { - [1, 2, 3] - |> foldr(_, [], fn(x, acc) { x :: acc }) - |> Assert:equal(_, [1, 2, 3]) -} diff --git a/src/Order.gleam b/src/Order.gleam deleted file mode 100644 index b0b43da..0000000 --- a/src/Order.gleam +++ /dev/null @@ -1,98 +0,0 @@ -pub enum Order = - | LT - | EQ - | GT -; - -import Order:* - -pub fn reverse(order) { - case order { - | LT => GT - | EQ => EQ - | GT => LT - } -} - -test reverse { - reverse(LT) |> Assert:equal(_, GT) - reverse(EQ) |> Assert:equal(_, EQ) - reverse(GT) |> Assert:equal(_, LT) -} - -pub fn to_int(order) { - case order { - | LT => -1 - | EQ => 0 - | GT => 1 - } -} - -test to_int { - to_int(LT) |> Assert:equal(_, -1) - to_int(EQ) |> Assert:equal(_, 0) - to_int(GT) |> Assert:equal(_, 1) -} - -pub fn compare(a, b) { - case {a, b} { - | {LT, LT} => EQ - | {LT, _} => LT - | {EQ, EQ} => EQ - | {GT, GT} => EQ - | {EQ, GT} => LT - | _ => GT - } -} - -test compare { - compare(LT, LT) |> Assert:equal(_, EQ) - compare(LT, EQ) |> Assert:equal(_, LT) - compare(LT, GT) |> Assert:equal(_, LT) - compare(EQ, LT) |> Assert:equal(_, GT) - compare(EQ, EQ) |> Assert:equal(_, EQ) - compare(EQ, GT) |> Assert:equal(_, LT) - compare(GT, LT) |> Assert:equal(_, GT) - compare(GT, EQ) |> Assert:equal(_, GT) - compare(GT, GT) |> Assert:equal(_, EQ) -} - -pub fn max(a, b) { - case {a, b} { - | {GT, _} => GT - | {EQ, LT} => EQ - | _ => b - } -} - -test max { - max(LT, LT) |> Assert:equal(_, LT) - max(LT, EQ) |> Assert:equal(_, EQ) - max(LT, GT) |> Assert:equal(_, GT) - max(EQ, LT) |> Assert:equal(_, EQ) - max(EQ, EQ) |> Assert:equal(_, EQ) - max(EQ, GT) |> Assert:equal(_, GT) - max(GT, LT) |> Assert:equal(_, GT) - max(GT, EQ) |> Assert:equal(_, GT) - max(GT, GT) |> Assert:equal(_, GT) -} - -pub fn min(a, b) { - case {a, b} { - | {LT, _} => LT - | {EQ, GT} => EQ - | _ => b - } -} - -test min { - min(LT, LT) |> Assert:equal(_, LT) - min(LT, EQ) |> Assert:equal(_, LT) - min(LT, GT) |> Assert:equal(_, LT) - min(EQ, LT) |> Assert:equal(_, LT) - min(EQ, EQ) |> Assert:equal(_, EQ) - min(EQ, GT) |> Assert:equal(_, EQ) - min(GT, LT) |> Assert:equal(_, LT) - min(GT, EQ) |> Assert:equal(_, EQ) - min(GT, GT) |> Assert:equal(_, GT) -} diff --git a/src/Result.gleam b/src/Result.gleam deleted file mode 100644 index 219b446..0000000 --- a/src/Result.gleam +++ /dev/null @@ -1,112 +0,0 @@ -doc """ -Result represents the result of something that may succeed or fail. -`Ok` means it was successful, `Error` means it failed. -""" -pub enum Result(error, value) = - | Ok(value) - | Error(error) -; - -import Result:* - -pub fn is_ok(result) { - case result { - | Error(_) => False - | Ok(_) => True - } -} - -test is_ok { - is_ok(Ok(1)) |> Assert:true - is_ok(Error(1)) |> Assert:false -} - -pub fn is_error(result) { - case result { - | Ok(_) => False - | Error(_) => True - } -} - -test is_error { - is_error(Ok(1)) |> Assert:false - is_error(Error(1)) |> Assert:true -} - -pub fn map(result, fun) { - case result { - | Ok(x) => fun(x) - | Error(_) => result - } -} - -test map { - Ok(1) - |> map(_, fn(x) { x + 1 }) - |> Assert:equal(_, Ok(2)) - Error(1) - |> map(_, fn(x) { x + 1 }) - |> Assert:equal(Error(1)) -} - -pub fn map_error(result, fun) { - case result { - | Ok(_) => result - | Error(error) => Error(fun(error)) - } -} - -test map_error { - Ok(1) - |> map_error(_, fn(x) { x + 1 }) - |> Assert:equal(_, Ok(1)) - Error(1) - |> map_error(_, fn(x) { x + 1 }) - |> Assert:equal(_, Error(2)) -} - -pub fn flatten(result) { - case result { - | Ok(x) => x - | Error(_) => result - } -} - -test flatten { - flatten(Ok(Ok(1))) - |> Assert:equal(_, Ok(1)) - flatten(Ok(Error(1))) - |> Assert:equal(_, Error(1)) - flatten(Error(1)) - |> Assert:equal(_, Error(1)) -} - -pub fn flat_map(result, fun) { - result - |> unwrap(_, fun) - |> flatten -} - -test flat_map { - Error(1) - |> flat_map(_, fn(x) { Ok(x + 1) }) - |> Assert:equal(_, Error(1)) - Ok(1) - |> flat_map(_, fn(x) { Ok(x + 1) }) - |> Assert:equal(_, Ok(2)) - Ok(1) - |> flat_map(_, fn(_) { Error(1) }) - |> Assert:equal(_, Error(1)) -} - -pub fn unwrap(result, default) { - case result { - | Ok(v) => v - | Error(_) => default - } -} - -test unwrap { - unwrap(Ok(1), 50) |> Assert:equal(_, 1) - unwrap(Error("nope"), 50) |> Assert:equal(_, 50) -} diff --git a/src/bool.gleam b/src/bool.gleam new file mode 100644 index 0000000..a4d6878 --- /dev/null +++ b/src/bool.gleam @@ -0,0 +1,102 @@ +import order:Order + +pub enum Bool = + | True + | False + +import Bool:* + +pub fn not(bool) { + case bool { + | True => False + | False => True + } +} + +test not { + not(True) + |> assert:false + + not(False) + |> assert:true +} + +pub fn compare(a, b) { + case (a, b) { + | (True, True) => Order:EQ + | (True, False) => Order:GT + | (False, False) => Order:EQ + | (False, True) => Order:GT + } +} + +test compare { + compare(True, True) + |> assert:equal(_, Order:EQ) + + compare(True, False) + |> assert:equal(_, Order:GT) + + compare(False, False) + |> assert:equal(_, Order:LT) + + compare(False, True) + |> assert:equal(_, Order:GT) +} + +pub fn max(a, b) { + case a { + | True => True + | False => b + } +} + +test max { + max(True, True) + |> assert:equal(_, True) + + max(True, False) + |> assert:equal(_, True) + + max(False, False) + |> assert:equal(_, False) + + max(False, True) + |> assert:equal(_, True) +} + +pub fn min(a, b) { + case a { + | False => False + | True => b + } +} + +test min { + min(True, True) + |> assert:equal(_, True) + + min(True, False) + |> assert:equal(_, False) + + min(False, False) + |> assert:equal(_, False) + + min(False, True) + |> assert:equal(_, False) +} + +pub fn to_int(bool) { + case bool { + | False => 0 + | True => 1 + } +} + +test to_int { + to_int(True) + |> assert:equal(_, 1) + + to_int(False) + |> assert:equal(_, 0) +} diff --git a/src/foreign.gleam b/src/foreign.gleam new file mode 100644 index 0000000..e921ea8 --- /dev/null +++ b/src/foreign.gleam @@ -0,0 +1,24 @@ +doc """ +Foreign data is data that we don't know the type of yet. +We likely get data like this from interop with Erlang, or from +IO with the outside world. +""" +pub external type Foreign +; + +doc """ +Convert any Gleam data into Foreign data. +""" +pub external fn new(a) => Foreign = 'Gleam.Foreign' 'identity' + +doc """ +Unsafely cast any type into any other type.o + +This is an escape hatch for the type system that may be useful when wrapping +native Erlang APIs. It is to be used as a last measure only. +""" +pub external fn unsafeCoerce(a) => b = 'Gleam.Foreign' 'identity' + +fn identity(x) { + x +} diff --git a/src/list.gleam b/src/list.gleam new file mode 100644 index 0000000..8c269f9 --- /dev/null +++ b/src/list.gleam @@ -0,0 +1,253 @@ +import assert +import result:Result:* +import bool:Bool:* + +pub enum Error = + | Empty + +import Error:* + +// Using the Erlang C BIF implementation. +// +pub external fn length(List(a)) => Int = 'erlang' 'length' + +test length { + length([]) |> assert:equal(_, 0) + length([1]) |> assert:equal(_, 1) + length([1, 1]) |> assert:equal(_, 2) + length([1, 1, 1]) |> assert:equal(_, 3) +} + +// Using the Erlang C BIF implementation. +// +pub external fn reverse(List(a)) => List(a) = 'erlang' 'reverse' + +test reverse { + length([]) |> assert:equal(_, []) + length([1, 2, 3, 4, 5]) |> assert:equal(_, [5, 4, 3, 2, 1]) +} + +pub fn is_empty(list) { + list == [] +} + +test is_empty { + is_empty([]) |> assert:true + is_empty([1]) |> assert:false +} + +pub fn member(list, elem) { + case list { + | [] => False + | elem :: _ => True + | _ :: rest => member(rest, elem) + } +} + +test is_member { + is_member([0, 4, 5, 1], 1) |> assert:true + is_member([0, 4, 5, 7], 1) |> assert:false + is_member([], 1) |> assert:false +} + +pub fn head(list) { + case list { + | [] => Error(Empty) + | elem :: _ => Ok(elem) + } +} + +test head { + head([0, 4, 5, 7]) + |> assert:equal(_, Ok(0)) + + head([]) + |> assert:equal(_, Error(Empty)) +} + +pub fn tail(list) { + case list { + | [] => Error(Empty) + | _ :: rest => Ok(rest) + } +} + +test tail { + tail([0, 4, 5, 7]) + |> assert:equal(_, Ok([4, 5, 7])) + + tail([0]) + |> assert:equal(_, Ok([])) + + tail([]) + |> assert:equal(_, Error(Empty)) +} + +pub fn filter(list, fun) { + filter(list, fun, []) +} + +test filter { + [] + |> filter(_, fn(x) { True }) + |> assert:equal(_, []) + + [0, 4, 5, 7, 3] + |> filter(_, fn(x) { True }) + |> assert:equal(_, [0, 4, 5, 7, 3]) + + [0, 4, 5, 7, 3] + |> filter(_, fn(x) { x > 4 }) + |> assert:equal(_, [5, 7]) + + [0, 4, 5, 7, 3] + |> filter(_, fn(x) { x < 4 }) + |> assert:equal(_, [0, 3]) +} + +fn do_filter(list, fun, acc) { + case list { + | [] => reverse(acc) + | x :: xs => + new_acc = + case fun(x) { + | True => x :: acc + | False => acc + } + do_filter(xs, fun, new_acc) + } +} + +pub fn map(list, fun) { + do_map(list, fun, []) +} + +test map { + [] + |> map(_, fn(x) { x * 2 }) + |> assert:equal(_, []) + + [0, 4, 5, 7, 3] + |> map(_, fn(x) { x * 2 }) + |> assert:equal(_, [0, 8, 10, 14, 6]) +} + +fn do_map(list, fun, acc) { + case list { + | [] => reverse(acc) + | x :: xs => do_map(xs, fun, fun(x) :: acc) + } +} + +pub fn drop(list, n) { + case n <= 0 { + | True => list + | False => + case list { + | [] => [] + | _ :: xs => drop(xs, n - 1) + } + } +} + +test drop/2 { + [] + |> drop(_, 5) + |> assert:equal(_, []) + + [1, 2, 3, 4, 5, 6, 7, 8] + |> drop(_, 5) + |> assert:equal(_, [6, 7, 8]) +} + +pub fn take(list, n) { + do_take(list, n, []) +} + +fn do_take(list, n, acc) { + case n <= 0 { + | True => reverse(acc) + | False => + case list { + | [] => reverse(acc) + | x :: xs => take(xs, n - 1, x :: acc) + } + } +} + +test take { + [] + |> take(_, 5) + |> assert:equal(_, []) + [1, 2, 3, 4, 5, 6, 7, 8] + |> take(_, 5) + |> assert:equal(_, [1, 2, 3, 4, 5]) +} + +pub fn of(x) { + [x] +} + +test of() { + of([]) |> assert:equal(_, [[]]) + of(1) |> assert:equal(_, [1]) +} + +pub fn new() { + [] +} + +test new() { + new() |> assert:equal(_, []) +} + +pub fn flatten(lists) { + do_flatten(lists, []) +} + +test flatten() { + flatten([]) + |> assert:equal(_, []) + + flatten([[]]) + |> assert:equal(_, []) + + flatten([[], [], []]) + |> assert:equal(_, []) + + flatten([[1, 2], [], [3, 4]]) + |> assert:equal(_, [1, 2, 3, 4]) +} + +fn do_flatten(lists, acc) { + case lists { + | [] => acc + | l :: rest => flatten(rest, acc ++ l) + } +} + +pub fn foldl(list, acc, fun) { + case list { + | [] => acc + | x :: rest => foldl(rest, fun(x, acc), fun) + } +} + +test foldl() { + [1, 2, 3] + |> foldl(_, [], fn(x, acc) { x :: acc }) + |> assert:equal(_, [3, 2, 1]) +} + +pub fn foldr(list, acc, fun) { + case list { + | [] => acc + | x :: rest => fun(x, foldl(rest, acc, fun)) + } +} + +test foldr() { + [1, 2, 3] + |> foldr(_, [], fn(x, acc) { x :: acc }) + |> assert:equal(_, [1, 2, 3]) +} diff --git a/src/order.gleam b/src/order.gleam new file mode 100644 index 0000000..dbeb8e1 --- /dev/null +++ b/src/order.gleam @@ -0,0 +1,100 @@ +import assert + +pub enum Order = + | LT + | EQ + | GT +; + +import Order:* + +pub fn reverse(order) { + case order { + | LT => GT + | EQ => EQ + | GT => LT + } +} + +test reverse { + reverse(LT) |> assert:equal(_, GT) + reverse(EQ) |> assert:equal(_, EQ) + reverse(GT) |> assert:equal(_, LT) +} + +pub fn to_int(order) { + case order { + | LT => -1 + | EQ => 0 + | GT => 1 + } +} + +test to_int { + to_int(LT) |> assert:equal(_, -1) + to_int(EQ) |> assert:equal(_, 0) + to_int(GT) |> assert:equal(_, 1) +} + +pub fn compare(a, b) { + case {a, b} { + | {LT, LT} => EQ + | {LT, _} => LT + | {EQ, EQ} => EQ + | {GT, GT} => EQ + | {EQ, GT} => LT + | _ => GT + } +} + +test compare { + compare(LT, LT) |> assert:equal(_, EQ) + compare(LT, EQ) |> assert:equal(_, LT) + compare(LT, GT) |> assert:equal(_, LT) + compare(EQ, LT) |> assert:equal(_, GT) + compare(EQ, EQ) |> assert:equal(_, EQ) + compare(EQ, GT) |> assert:equal(_, LT) + compare(GT, LT) |> assert:equal(_, GT) + compare(GT, EQ) |> assert:equal(_, GT) + compare(GT, GT) |> assert:equal(_, EQ) +} + +pub fn max(a, b) { + case {a, b} { + | {GT, _} => GT + | {EQ, LT} => EQ + | _ => b + } +} + +test max { + max(LT, LT) |> assert:equal(_, LT) + max(LT, EQ) |> assert:equal(_, EQ) + max(LT, GT) |> assert:equal(_, GT) + max(EQ, LT) |> assert:equal(_, EQ) + max(EQ, EQ) |> assert:equal(_, EQ) + max(EQ, GT) |> assert:equal(_, GT) + max(GT, LT) |> assert:equal(_, GT) + max(GT, EQ) |> assert:equal(_, GT) + max(GT, GT) |> assert:equal(_, GT) +} + +pub fn min(a, b) { + case {a, b} { + | {LT, _} => LT + | {EQ, GT} => EQ + | _ => b + } +} + +test min { + min(LT, LT) |> assert:equal(_, LT) + min(LT, EQ) |> assert:equal(_, LT) + min(LT, GT) |> assert:equal(_, LT) + min(EQ, LT) |> assert:equal(_, LT) + min(EQ, EQ) |> assert:equal(_, EQ) + min(EQ, GT) |> assert:equal(_, EQ) + min(GT, LT) |> assert:equal(_, LT) + min(GT, EQ) |> assert:equal(_, EQ) + min(GT, GT) |> assert:equal(_, GT) +} diff --git a/src/result.gleam b/src/result.gleam new file mode 100644 index 0000000..996d92a --- /dev/null +++ b/src/result.gleam @@ -0,0 +1,114 @@ +import assert + +doc """ +Result represents the result of something that may succeed or fail. +`Ok` means it was successful, `Error` means it failed. +""" +pub enum Result(error, value) = + | Ok(value) + | Error(error) +; + +import Result:* + +pub fn is_ok(result) { + case result { + | Error(_) => False + | Ok(_) => True + } +} + +test is_ok { + is_ok(Ok(1)) |> assert:true + is_ok(Error(1)) |> assert:false +} + +pub fn is_error(result) { + case result { + | Ok(_) => False + | Error(_) => True + } +} + +test is_error { + is_error(Ok(1)) |> assert:false + is_error(Error(1)) |> assert:true +} + +pub fn map(result, fun) { + case result { + | Ok(x) => fun(x) + | Error(_) => result + } +} + +test map { + Ok(1) + |> map(_, fn(x) { x + 1 }) + |> assert:equal(_, Ok(2)) + Error(1) + |> map(_, fn(x) { x + 1 }) + |> assert:equal(Error(1)) +} + +pub fn map_error(result, fun) { + case result { + | Ok(_) => result + | Error(error) => Error(fun(error)) + } +} + +test map_error { + Ok(1) + |> map_error(_, fn(x) { x + 1 }) + |> assert:equal(_, Ok(1)) + Error(1) + |> map_error(_, fn(x) { x + 1 }) + |> assert:equal(_, Error(2)) +} + +pub fn flatten(result) { + case result { + | Ok(x) => x + | Error(_) => result + } +} + +test flatten { + flatten(Ok(Ok(1))) + |> assert:equal(_, Ok(1)) + flatten(Ok(Error(1))) + |> assert:equal(_, Error(1)) + flatten(Error(1)) + |> assert:equal(_, Error(1)) +} + +pub fn flat_map(result, fun) { + result + |> unwrap(_, fun) + |> flatten +} + +test flat_map { + Error(1) + |> flat_map(_, fn(x) { Ok(x + 1) }) + |> assert:equal(_, Error(1)) + Ok(1) + |> flat_map(_, fn(x) { Ok(x + 1) }) + |> assert:equal(_, Ok(2)) + Ok(1) + |> flat_map(_, fn(_) { Error(1) }) + |> assert:equal(_, Error(1)) +} + +pub fn unwrap(result, default) { + case result { + | Ok(v) => v + | Error(_) => default + } +} + +test unwrap { + unwrap(Ok(1), 50) |> assert:equal(_, 1) + unwrap(Error("nope"), 50) |> assert:equal(_, 50) +} -- cgit v1.2.3