From 2c2541750ca4b7b604070c75c18d84be833c97d5 Mon Sep 17 00:00:00 2001 From: Louis Pilfold Date: Tue, 25 Jun 2019 22:48:07 +0100 Subject: stdlib namespace std -> gleam --- src/gleam/any.gleam | 53 ++++++++ src/gleam/atom.gleam | 17 +++ src/gleam/bool.gleam | 38 ++++++ src/gleam/expect.gleam | 20 ++++ src/gleam/float.gleam | 21 ++++ src/gleam/http.gleam | 13 ++ src/gleam/int.gleam | 21 ++++ src/gleam/iodata.gleam | 58 +++++++++ src/gleam/list.gleam | 306 +++++++++++++++++++++++++++++++++++++++++++++++ src/gleam/map_dict.gleam | 100 ++++++++++++++++ src/gleam/order.gleam | 48 ++++++++ src/gleam/result.gleam | 51 ++++++++ src/gleam/string.gleam | 36 ++++++ src/gleam/tuple.gleam | 29 +++++ src/std/any.gleam | 53 -------- src/std/atom.gleam | 17 --- src/std/bool.gleam | 38 ------ src/std/expect.gleam | 20 ---- src/std/float.gleam | 21 ---- src/std/http.gleam | 13 -- src/std/int.gleam | 21 ---- src/std/iodata.gleam | 58 --------- src/std/list.gleam | 306 ----------------------------------------------- src/std/map_dict.gleam | 100 ---------------- src/std/order.gleam | 48 -------- src/std/result.gleam | 51 -------- src/std/string.gleam | 36 ------ src/std/tuple.gleam | 29 ----- 28 files changed, 811 insertions(+), 811 deletions(-) create mode 100644 src/gleam/any.gleam create mode 100644 src/gleam/atom.gleam create mode 100644 src/gleam/bool.gleam create mode 100644 src/gleam/expect.gleam create mode 100644 src/gleam/float.gleam create mode 100644 src/gleam/http.gleam create mode 100644 src/gleam/int.gleam create mode 100644 src/gleam/iodata.gleam create mode 100644 src/gleam/list.gleam create mode 100644 src/gleam/map_dict.gleam create mode 100644 src/gleam/order.gleam create mode 100644 src/gleam/result.gleam create mode 100644 src/gleam/string.gleam create mode 100644 src/gleam/tuple.gleam delete mode 100644 src/std/any.gleam delete mode 100644 src/std/atom.gleam delete mode 100644 src/std/bool.gleam delete mode 100644 src/std/expect.gleam delete mode 100644 src/std/float.gleam delete mode 100644 src/std/http.gleam delete mode 100644 src/std/int.gleam delete mode 100644 src/std/iodata.gleam delete mode 100644 src/std/list.gleam delete mode 100644 src/std/map_dict.gleam delete mode 100644 src/std/order.gleam delete mode 100644 src/std/result.gleam delete mode 100644 src/std/string.gleam delete mode 100644 src/std/tuple.gleam (limited to 'src') diff --git a/src/gleam/any.gleam b/src/gleam/any.gleam new file mode 100644 index 0000000..44e2dd8 --- /dev/null +++ b/src/gleam/any.gleam @@ -0,0 +1,53 @@ +import gleam/list as list_mod +import gleam/atom +import gleam/result + +// `Any` 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 Any; + +// Convert any Gleam data into `Any` data. +// +pub external fn from(a) -> Any = "gleam__stdlib" "identity"; + +// Unsafely cast any type into any other type. +// +// 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 unsafe_coerce(a) -> b = "gleam__stdlib" "identity"; + +pub external fn string(Any) -> Result(String, String) + = "gleam__stdlib" "decode_string" + +pub external fn int(Any) -> Result(Int, String) + = "gleam__stdlib" "decode_int" + +pub external fn float(Any) -> Result(Float, String) + = "gleam__stdlib" "decode_float" + +pub external fn atom(Any) -> Result(atom:Atom, String) + = "gleam__stdlib" "decode_atom" + +pub external fn bool(Any) -> Result(Bool, String) + = "gleam__stdlib" "decode_bool" + +pub external fn thunk(Any) -> Result(fn() -> Any, String) + = "gleam__stdlib" "decode_thunk" + +external fn list_any(Any) -> Result(List(Any), String) = + "gleam__stdlib" "decode_list" + +pub fn list(any, decode) { + any + |> list_any + |> result:then(_, list_mod:traverse(_, decode)) +} + +pub external fn tuple(Any) -> Result({Any, Any}, String) + = "gleam__stdlib" "decode_tuple" + +pub external fn field(Any, a) -> Result(Any, String) + = "gleam__stdlib" "decode_field" diff --git a/src/gleam/atom.gleam b/src/gleam/atom.gleam new file mode 100644 index 0000000..67d040d --- /dev/null +++ b/src/gleam/atom.gleam @@ -0,0 +1,17 @@ +pub external type Atom; + +pub enum AtomNotLoaded = + | AtomNotLoaded + +pub external fn from_string(String) -> Result(Atom, AtomNotLoaded) = + "gleam__stdlib" "atom_from_string"; + +// This function can create a new atom if one does not already exist for +// the given string. Atoms are not garbage collected so this can result +// in a memory leak if called over time on new values +// +pub external fn create_from_string(String) -> Atom = + "gleam__stdlib" "atom_create_from_string"; + +pub external fn to_string(Atom) -> String = + "gleam__stdlib" "atom_to_string"; diff --git a/src/gleam/bool.gleam b/src/gleam/bool.gleam new file mode 100644 index 0000000..e99333b --- /dev/null +++ b/src/gleam/bool.gleam @@ -0,0 +1,38 @@ +import gleam/order + +pub fn negate(bool) { + case bool { + | True -> False + | False -> True + } +} + +pub fn compare(a, b) { + case {a, b} { + | {True, True} -> order:Eq + | {True, False} -> order:Gt + | {False, False} -> order:Eq + | {False, True} -> order:Lt + } +} + +pub fn max(a, b) { + case a { + | True -> True + | False -> b + } +} + +pub fn min(a, b) { + case a { + | False -> False + | True -> b + } +} + +pub fn to_int(bool) { + case bool { + | False -> 0 + | True -> 1 + } +} diff --git a/src/gleam/expect.gleam b/src/gleam/expect.gleam new file mode 100644 index 0000000..5ea6a93 --- /dev/null +++ b/src/gleam/expect.gleam @@ -0,0 +1,20 @@ +// TODO: Move this module into another package so it can be used as a +// dep only in test. + +pub external type Expectation; + +pub external fn equal(a, a) -> Expectation = "gleam__stdlib" "expect_equal"; + +pub external fn not_equal(a, a) -> Expectation = "gleam__stdlib" "expect_not_equal"; + +pub external fn true(Bool) -> Expectation = "gleam__stdlib" "expect_true"; + +pub external fn false(Bool) -> Expectation = "gleam__stdlib" "expect_false"; + +pub external fn is_ok(Result(a, b)) -> Expectation = "gleam__stdlib" "expect_is_ok"; + +pub external fn is_error(Result(a, b)) -> Expectation = "gleam__stdlib" "expect_is_error"; + +pub fn fail() { + true(False) +} diff --git a/src/gleam/float.gleam b/src/gleam/float.gleam new file mode 100644 index 0000000..b1ae86e --- /dev/null +++ b/src/gleam/float.gleam @@ -0,0 +1,21 @@ +import gleam/iodata + +pub enum NotAFloat = + | NotAFloat + +pub external fn parse(String) -> Result(Float, NotAFloat) = + "gleam__stdlib" "parse_float"; + +pub fn to_string(f) { + f + |> iodata:from_float + |> iodata:to_string +} + +pub external fn ceiling(Float) -> Float = "math" "ceil"; + +pub external fn floor(Float) -> Float = "math" "floor"; + +pub external fn round(Float) -> Int = "erlang" "round"; + +pub external fn truncate(Float) -> Int = "erlang" "trunc"; diff --git a/src/gleam/http.gleam b/src/gleam/http.gleam new file mode 100644 index 0000000..d9942a8 --- /dev/null +++ b/src/gleam/http.gleam @@ -0,0 +1,13 @@ +// HTTP standard method as defined by RFC 2616, and PATCH which is defined by +// RFC 5789. +// +pub enum Method = + | Get + | Post + | Head + | Put + | Delete + | Trace + | Connect + | Options + | Patch diff --git a/src/gleam/int.gleam b/src/gleam/int.gleam new file mode 100644 index 0000000..c4fbf6f --- /dev/null +++ b/src/gleam/int.gleam @@ -0,0 +1,21 @@ +import gleam/order + +pub enum NotAnInt = + | NotAnInt + +pub external fn parse(String) -> Result(Int, NotAnInt) = "gleam__stdlib" "parse_int"; + +pub external fn to_string(Int) -> String = "erlang" "integer_to_binary" + +pub external fn to_base_string(Int, Int) -> String = "erlang" "integer_to_binary" + +pub fn compare(a, b) { + case a == b { + | True -> order:Eq + | False -> + case a < b { + | True -> order:Lt + | False -> order:Gt + } + } +} diff --git a/src/gleam/iodata.gleam b/src/gleam/iodata.gleam new file mode 100644 index 0000000..56efc65 --- /dev/null +++ b/src/gleam/iodata.gleam @@ -0,0 +1,58 @@ +pub external type Iodata; + +pub external fn prepend(Iodata, String) -> Iodata = + "gleam__stdlib" "iodata_prepend"; + +pub external fn append(Iodata, String) -> Iodata = + "gleam__stdlib" "iodata_append"; + +pub external fn prepend_iodata(Iodata, Iodata) -> Iodata = + "gleam__stdlib" "iodata_prepend"; + +pub external fn append_iodata(Iodata, Iodata) -> Iodata = + "gleam__stdlib" "iodata_append"; + +pub external fn from_strings(List(String)) -> Iodata = + "gleam__stdlib" "identity"; + +pub external fn concat(List(Iodata)) -> Iodata = + "gleam__stdlib" "identity"; + +pub external fn new(String) -> Iodata = + "gleam__stdlib" "identity"; + +pub external fn to_string(Iodata) -> String = + "erlang" "iolist_to_binary"; + +pub external fn byte_size(Iodata) -> Int = + "erlang" "iolist_size"; + +pub external fn from_float(Float) -> Iodata = + "io_lib_format" "fwrite_g"; + +pub external fn lowercase(Iodata) -> Iodata = "string" "lowercase" + +pub external fn uppercase(Iodata) -> Iodata = "string" "uppercase" + +pub external fn reverse(Iodata) -> Iodata = "string" "reverse" + +enum Direction = + | All + +external fn erl_split(Iodata, String, Direction) -> List(Iodata) = + "string" "split" + +pub fn split(iodata, on) { + erl_split(iodata, on, All) +} + +external fn erl_replace(Iodata, String, String, Direction) -> Iodata = + "string" "replace" + +pub fn replace(iodata, pattern, replacement) { + erl_replace(iodata, pattern, replacement, All) +} + +pub external fn is_equal(Iodata, Iodata) -> Bool = "string" "equal" + +pub external fn is_empty(Iodata) -> Bool = "string" "is_empty" diff --git a/src/gleam/list.gleam b/src/gleam/list.gleam new file mode 100644 index 0000000..96ed75e --- /dev/null +++ b/src/gleam/list.gleam @@ -0,0 +1,306 @@ +import gleam/int +import gleam/order + +pub enum Empty = + | Empty + +pub enum NotFound = + | NotFound + +pub enum LengthMismatch = + | LengthMismatch + +// Using the Erlang C BIF implementation. +// +pub external fn length(List(a)) -> Int = "erlang" "length" + +// Using the Erlang C BIF implementation. +// +pub external fn reverse(List(a)) -> List(a) = "lists" "reverse" + +pub fn is_empty(list) { + list == [] +} + +pub fn contains(list, elem) { + case list { + | [] -> False + | [head | rest] -> head == elem || contains(rest, elem) + } +} + +pub fn head(list) { + case list { + | [] -> Error(Empty) + | [x | _] -> Ok(x) + } +} + +pub fn tail(list) { + case list { + | [] -> Error(Empty) + | [_ | xs] -> Ok(xs) + } +} + +fn do_filter(list, fun, acc) { + case list { + | [] -> reverse(acc) + | [x | xs] -> + let new_acc = + case fun(x) { + | True -> [x | acc] + | False -> acc + } + do_filter(xs, fun, new_acc) + } +} + +pub fn filter(list, fun) { + do_filter(list, fun, []) +} + +fn do_map(list, fun, acc) { + case list { + | [] -> reverse(acc) + | [x | xs] -> do_map(xs, fun, [fun(x) | acc]) + } +} + +pub fn map(list, fun) { + do_map(list, fun, []) +} + +fn do_index_map(list, fun, index, acc) { + case list { + | [] -> reverse(acc) + | [x | xs] -> do_index_map(xs, fun, index + 1, [fun(index, x) | acc]) + } +} + +pub fn index_map(list, fun) { + do_index_map(list, fun, 0, []) +} + +fn do_traverse(list, fun, acc) { + case list { + | [] -> Ok(reverse(acc)) + | [x | xs] -> + case fun(x) { + | Ok(y) -> do_traverse(xs, fun, [y | acc]) + | Error(error) -> Error(error) + } + } +} + +pub fn traverse(list, fun) { + do_traverse(list, fun, []) +} + +pub fn drop(list, n) { + case n <= 0 { + | True -> list + | False -> + case list { + | [] -> [] + | [_ | xs] -> drop(xs, n - 1) + } + } +} + +fn do_take(list, n, acc) { + case n <= 0 { + | True -> reverse(acc) + | False -> + case list { + | [] -> reverse(acc) + | [x | xs] -> do_take(xs, n - 1, [x | acc]) + } + } +} + +pub fn take(list, n) { + do_take(list, n, []) +} + +pub fn new() { + [] +} + +pub external fn append(List(a), List(a)) -> List(a) = "lists" "append"; + +fn do_flatten(lists, acc) { + case lists { + | [] -> acc + | [l | rest] -> do_flatten(rest, append(acc, l)) + } +} + +pub fn flatten(lists) { + do_flatten(lists, []) +} + +pub fn fold(list, acc, fun) { + case list { + | [] -> acc + | [x | rest] -> fold(rest, fun(x, acc), fun) + } +} + +pub fn fold_right(list, acc, fun) { + case list { + | [] -> acc + | [x | rest] -> fun(x, fold_right(rest, acc, fun)) + } +} + +pub fn find(haystack, f) { + case haystack { + | [] -> Error(NotFound) + | [x | rest] -> + case f(x) { + | Ok(x) -> Ok(x) + | _ -> find(rest, f) + } + } +} + +pub fn all(list, f) { + case list { + | [] -> True + | [x | rest] -> + case f(x) { + | True -> all(rest, f) + | _ -> False + } + } +} + +pub fn any(list, f) { + case list { + | [] -> False + | [ x | rest] -> + case f(x) { + | False -> any(rest, f) + | _ -> True + } + } +} + +pub fn zip(l1, l2) { + case {l1, l2} { + | {[], _} -> [] + | {_, []} -> [] + | {[x1 | rest1], [x2 | rest2] } -> [ {x1, x2} | zip(rest1, rest2) ] + } +} + +pub fn strict_zip(l1, l2) { + case length(l1) == length(l2) { + | True -> Ok(zip(l1, l2)) + | False -> Error(LengthMismatch) + } +} + +pub fn intersperse(list, elem) { + case list { + | [] -> [] + | [x | []] -> [x] + | [x | rest] -> [x | [elem | intersperse(rest, elem)]] + } +} + +pub fn at(list, i) { + case i < 0 { + | True -> Error(NotFound) + | False -> + case list { + | [] -> Error(NotFound) + | [x | rest] -> + case i == 0 { + | True -> Ok(x) + | False -> at(rest, i - 1) + } + } + } +} + +pub fn unique(list) { + case list { + | [] -> [] + | [x | rest] -> [x | unique(filter(rest, fn(y) { y != x }))] + } +} + +fn merge_sort(a, b) { + case {a, b} { + | {[], _} -> b + | {_, []} -> a + | {[ax | ar], [bx | br]} -> + case ax < bx { + | True -> [ax | merge_sort(ar, b)] + | False -> [bx | merge_sort(a, br)] + } + } +} + +pub fn sort(list) { + let list_length = length(list) + case list_length < 2 { + | True -> list + | False -> + let split_length = list_length / 2 + let a_list = take(list, split_length) + let b_list = drop(list, split_length) + merge_sort(sort(a_list), sort(b_list)) + } +} + +pub fn range(start, stop) { + case int:compare(start, stop) { + | order:Eq -> [] + | order:Gt -> [start | range(start - 1, stop)] + | order:Lt -> [start | range(start + 1, stop)] + } +} + +fn do_repeat(a, times, acc) { + case times <= 0 { + | True -> acc + | False -> do_repeat(a, times - 1, [a | acc]) + } +} + +pub fn repeat(a, times) { + do_repeat(a, times, []) +} + +fn do_split(list, n, taken) { + case n <= 0 { + | True -> {reverse(taken), list} + | False -> + case list { + | [] -> {reverse(taken), []} + | [x | xs] -> do_split(xs, n - 1, [x | taken]) + } + } +} + +pub fn split(list, n) { + do_split(list, n, []) +} + +fn do_split_while(list, f, acc) { + case list { + | [] -> {reverse(acc), []} + | [x | xs] -> + case f(x) { + | False -> {reverse(acc), list} + | _ -> do_split_while(xs, f, [x | acc]) + } + } +} + +pub fn split_while(list, f) { + do_split_while(list, f, []) +} diff --git a/src/gleam/map_dict.gleam b/src/gleam/map_dict.gleam new file mode 100644 index 0000000..bf3ed87 --- /dev/null +++ b/src/gleam/map_dict.gleam @@ -0,0 +1,100 @@ +import gleam/any +import gleam/result +import gleam/list + +pub external type MapDict(key, value); + +pub enum NotFound = + | NotFound + +pub external fn size(MapDict(k, v)) -> Int + = "maps" "size" + +pub external fn to_list(MapDict(key, value)) -> List({key, value}) + = "maps" "to_list" + +pub external fn from_list(List({key, value})) -> MapDict(key, value) + = "maps" "from_list" + +external fn is_key(key, MapDict(key, v)) -> Bool + = "maps" "is_key" + +pub fn has_key(map, key) { + is_key(key, map) +} + +pub external fn new() -> MapDict(key, value) + = "maps" "new" + +pub external fn fetch(MapDict(key, value), key) -> Result(value, NotFound) + = "gleam__stdlib" "map_fetch"; + +external fn erl_put(key, value, MapDict(key, value)) -> MapDict(key, value) + = "maps" "put"; + +pub fn put(map, key, value) { + erl_put(key, value, map) +} + +external fn erl_map_values(fn(key, value) -> value, MapDict(key, value)) + -> MapDict(key, value) + = "maps" "map"; + +pub fn map_values(map, fun) { + erl_map_values(fun, map) +} + +pub external fn keys(MapDict(keys, v)) -> List(keys) + = "maps" "keys" + +pub external fn values(MapDict(k, values)) -> List(values) + = "maps" "values" + +external fn erl_filter(fn(key, value) -> Bool, MapDict(key, value)) + -> MapDict(key, value) + = "maps" "filter"; + +pub fn filter(map, fun) { + erl_filter(fun, map) +} + +external fn erl_take(List(k), MapDict(k, v)) -> MapDict(k, v) = "maps" "with" + +pub fn take(map, keys) { + erl_take(keys, map) +} + +pub external fn merge(MapDict(k, v), MapDict(k, v)) -> MapDict(k, v) = "maps" "merge" + +external fn erl_delete(k, MapDict(k, v)) -> MapDict(k, v) = "maps" "remove" + +pub fn delete(map, key) { + erl_delete(key, map) +} + +pub fn drop(map, keys) { + list:fold(keys, map, fn(key, acc) { + delete(acc, key) + }) +} + +pub external type NotFound; + +pub fn update(dict, key, f) { + case fetch(dict, key) { + | Ok(value) -> put(dict, key, f(Ok(value))) + | Error(_) -> put(dict, key, f(Error(NotFound))) + } +} + +fn do_fold(list, acc, f) { + case list { + | [] -> acc + | [{k, v} | tail] -> do_fold(tail, f(k, v, acc), f) + } +} + +pub fn fold(dict, acc, f) { + let kvs = to_list(dict) + do_fold(kvs, acc, f) +} diff --git a/src/gleam/order.gleam b/src/gleam/order.gleam new file mode 100644 index 0000000..4d39705 --- /dev/null +++ b/src/gleam/order.gleam @@ -0,0 +1,48 @@ +pub enum Order = + | Lt + | Eq + | Gt +; + +pub fn reverse(order) { + case order { + | Lt -> Gt + | Eq -> Eq + | Gt -> Lt + } +} + +pub fn to_int(order) { + case order { + | Lt -> -1 + | Eq -> 0 + | Gt -> 1 + } +} + +pub fn compare(a, b) { + case {a, b} { + | {Lt, Lt} -> Eq + | {Lt, _} -> Lt + | {Eq, Eq} -> Eq + | {Gt, Gt} -> Eq + | {Eq, Gt} -> Lt + | _ -> Gt + } +} + +pub fn max(a, b) { + case {a, b} { + | {Gt, _} -> Gt + | {Eq, Lt} -> Eq + | _ -> b + } +} + +pub fn min(a, b) { + case {a, b} { + | {Lt, _} -> Lt + | {Eq, Gt} -> Eq + | _ -> b + } +} diff --git a/src/gleam/result.gleam b/src/gleam/result.gleam new file mode 100644 index 0000000..133d9d5 --- /dev/null +++ b/src/gleam/result.gleam @@ -0,0 +1,51 @@ +// Result represents the result of something that may succeed or fail. +// `Ok` means it was successful, `Error` means it failed. + +pub fn is_ok(result) { + case result { + | Error(_) -> False + | Ok(_) -> True + } +} + +pub fn is_error(result) { + case result { + | Ok(_) -> False + | Error(_) -> True + } +} + +pub fn map(result, fun) { + case result { + | Ok(x) -> Ok(fun(x)) + | Error(e) -> Error(e) + } +} + +pub fn map_error(result, fun) { + case result { + | Ok(_) -> result + | Error(error) -> Error(fun(error)) + } +} + +pub fn flatten(result) { + case result { + | Ok(x) -> x + | Error(error) -> Error(error) + } +} + +pub fn then(result, fun) { + case result { + | Ok(x) -> fun(x) + | Error(e) -> Error(e) + } +} + +pub fn unwrap(result, default) { + case result { + | Ok(v) -> v + | Error(_) -> default + } +} diff --git a/src/gleam/string.gleam b/src/gleam/string.gleam new file mode 100644 index 0000000..cc759a6 --- /dev/null +++ b/src/gleam/string.gleam @@ -0,0 +1,36 @@ +import gleam/iodata +import gleam/list + +pub external fn length(String) -> Int = "string" "length" + +pub enum ParseError = + | ParseError + +pub external fn lowercase(String) -> String = "string" "lowercase" + +pub external fn uppercase(String) -> String = "string" "uppercase" + +pub fn reverse(string) { + string + |> iodata:new + |> iodata:reverse + |> iodata:to_string +} + +pub fn split(string, on) { + string + |> iodata:new + |> iodata:split(_, on) + |> list:map(_, iodata:to_string) +} + +pub fn replace(string, pattern, with) { + string + |> iodata:new + |> iodata:replace(_, pattern, with) + |> iodata:to_string +} + +pub fn append(s1, s2) { + iodata:new(s1) |> iodata:append(_, s2) |> iodata:to_string(_) +} diff --git a/src/gleam/tuple.gleam b/src/gleam/tuple.gleam new file mode 100644 index 0000000..05968d0 --- /dev/null +++ b/src/gleam/tuple.gleam @@ -0,0 +1,29 @@ +import gleam/list + +pub fn new(a, b) { + {a, b} +} + +pub fn first(tup) { + let {a, _} = tup + a +} + +pub fn second(tup) { + let {_, a} = tup + a +} + +pub fn swap(tup) { + let {a, b} = tup + {b, a} +} + +pub fn fetch(haystack, needle) { + list:find(haystack, fn(tuple) { + case first(tuple) == needle { + | True -> tuple |> second |> Ok + | False -> Error([]) + } + }) +} diff --git a/src/std/any.gleam b/src/std/any.gleam deleted file mode 100644 index ac902cd..0000000 --- a/src/std/any.gleam +++ /dev/null @@ -1,53 +0,0 @@ -import std/list as list_mod -import std/atom -import std/result - -// `Any` 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 Any; - -// Convert any Gleam data into `Any` data. -// -pub external fn from(a) -> Any = "gleam__stdlib" "identity"; - -// Unsafely cast any type into any other type. -// -// 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 unsafe_coerce(a) -> b = "gleam__stdlib" "identity"; - -pub external fn string(Any) -> Result(String, String) - = "gleam__stdlib" "decode_string" - -pub external fn int(Any) -> Result(Int, String) - = "gleam__stdlib" "decode_int" - -pub external fn float(Any) -> Result(Float, String) - = "gleam__stdlib" "decode_float" - -pub external fn atom(Any) -> Result(atom:Atom, String) - = "gleam__stdlib" "decode_atom" - -pub external fn bool(Any) -> Result(Bool, String) - = "gleam__stdlib" "decode_bool" - -pub external fn thunk(Any) -> Result(fn() -> Any, String) - = "gleam__stdlib" "decode_thunk" - -external fn list_any(Any) -> Result(List(Any), String) = - "gleam__stdlib" "decode_list" - -pub fn list(any, decode) { - any - |> list_any - |> result:then(_, list_mod:traverse(_, decode)) -} - -pub external fn tuple(Any) -> Result({Any, Any}, String) - = "gleam__stdlib" "decode_tuple" - -pub external fn field(Any, a) -> Result(Any, String) - = "gleam__stdlib" "decode_field" diff --git a/src/std/atom.gleam b/src/std/atom.gleam deleted file mode 100644 index 67d040d..0000000 --- a/src/std/atom.gleam +++ /dev/null @@ -1,17 +0,0 @@ -pub external type Atom; - -pub enum AtomNotLoaded = - | AtomNotLoaded - -pub external fn from_string(String) -> Result(Atom, AtomNotLoaded) = - "gleam__stdlib" "atom_from_string"; - -// This function can create a new atom if one does not already exist for -// the given string. Atoms are not garbage collected so this can result -// in a memory leak if called over time on new values -// -pub external fn create_from_string(String) -> Atom = - "gleam__stdlib" "atom_create_from_string"; - -pub external fn to_string(Atom) -> String = - "gleam__stdlib" "atom_to_string"; diff --git a/src/std/bool.gleam b/src/std/bool.gleam deleted file mode 100644 index 985f0d6..0000000 --- a/src/std/bool.gleam +++ /dev/null @@ -1,38 +0,0 @@ -import std/order - -pub fn negate(bool) { - case bool { - | True -> False - | False -> True - } -} - -pub fn compare(a, b) { - case {a, b} { - | {True, True} -> order:Eq - | {True, False} -> order:Gt - | {False, False} -> order:Eq - | {False, True} -> order:Lt - } -} - -pub fn max(a, b) { - case a { - | True -> True - | False -> b - } -} - -pub fn min(a, b) { - case a { - | False -> False - | True -> b - } -} - -pub fn to_int(bool) { - case bool { - | False -> 0 - | True -> 1 - } -} diff --git a/src/std/expect.gleam b/src/std/expect.gleam deleted file mode 100644 index 5ea6a93..0000000 --- a/src/std/expect.gleam +++ /dev/null @@ -1,20 +0,0 @@ -// TODO: Move this module into another package so it can be used as a -// dep only in test. - -pub external type Expectation; - -pub external fn equal(a, a) -> Expectation = "gleam__stdlib" "expect_equal"; - -pub external fn not_equal(a, a) -> Expectation = "gleam__stdlib" "expect_not_equal"; - -pub external fn true(Bool) -> Expectation = "gleam__stdlib" "expect_true"; - -pub external fn false(Bool) -> Expectation = "gleam__stdlib" "expect_false"; - -pub external fn is_ok(Result(a, b)) -> Expectation = "gleam__stdlib" "expect_is_ok"; - -pub external fn is_error(Result(a, b)) -> Expectation = "gleam__stdlib" "expect_is_error"; - -pub fn fail() { - true(False) -} diff --git a/src/std/float.gleam b/src/std/float.gleam deleted file mode 100644 index 8e1904e..0000000 --- a/src/std/float.gleam +++ /dev/null @@ -1,21 +0,0 @@ -import std/iodata - -pub enum NotAFloat = - | NotAFloat - -pub external fn parse(String) -> Result(Float, NotAFloat) = - "gleam__stdlib" "parse_float"; - -pub fn to_string(f) { - f - |> iodata:from_float - |> iodata:to_string -} - -pub external fn ceiling(Float) -> Float = "math" "ceil"; - -pub external fn floor(Float) -> Float = "math" "floor"; - -pub external fn round(Float) -> Int = "erlang" "round"; - -pub external fn truncate(Float) -> Int = "erlang" "trunc"; diff --git a/src/std/http.gleam b/src/std/http.gleam deleted file mode 100644 index d9942a8..0000000 --- a/src/std/http.gleam +++ /dev/null @@ -1,13 +0,0 @@ -// HTTP standard method as defined by RFC 2616, and PATCH which is defined by -// RFC 5789. -// -pub enum Method = - | Get - | Post - | Head - | Put - | Delete - | Trace - | Connect - | Options - | Patch diff --git a/src/std/int.gleam b/src/std/int.gleam deleted file mode 100644 index b1f8256..0000000 --- a/src/std/int.gleam +++ /dev/null @@ -1,21 +0,0 @@ -import std/order - -pub enum NotAnInt = - | NotAnInt - -pub external fn parse(String) -> Result(Int, NotAnInt) = "gleam__stdlib" "parse_int"; - -pub external fn to_string(Int) -> String = "erlang" "integer_to_binary" - -pub external fn to_base_string(Int, Int) -> String = "erlang" "integer_to_binary" - -pub fn compare(a, b) { - case a == b { - | True -> order:Eq - | False -> - case a < b { - | True -> order:Lt - | False -> order:Gt - } - } -} diff --git a/src/std/iodata.gleam b/src/std/iodata.gleam deleted file mode 100644 index 56efc65..0000000 --- a/src/std/iodata.gleam +++ /dev/null @@ -1,58 +0,0 @@ -pub external type Iodata; - -pub external fn prepend(Iodata, String) -> Iodata = - "gleam__stdlib" "iodata_prepend"; - -pub external fn append(Iodata, String) -> Iodata = - "gleam__stdlib" "iodata_append"; - -pub external fn prepend_iodata(Iodata, Iodata) -> Iodata = - "gleam__stdlib" "iodata_prepend"; - -pub external fn append_iodata(Iodata, Iodata) -> Iodata = - "gleam__stdlib" "iodata_append"; - -pub external fn from_strings(List(String)) -> Iodata = - "gleam__stdlib" "identity"; - -pub external fn concat(List(Iodata)) -> Iodata = - "gleam__stdlib" "identity"; - -pub external fn new(String) -> Iodata = - "gleam__stdlib" "identity"; - -pub external fn to_string(Iodata) -> String = - "erlang" "iolist_to_binary"; - -pub external fn byte_size(Iodata) -> Int = - "erlang" "iolist_size"; - -pub external fn from_float(Float) -> Iodata = - "io_lib_format" "fwrite_g"; - -pub external fn lowercase(Iodata) -> Iodata = "string" "lowercase" - -pub external fn uppercase(Iodata) -> Iodata = "string" "uppercase" - -pub external fn reverse(Iodata) -> Iodata = "string" "reverse" - -enum Direction = - | All - -external fn erl_split(Iodata, String, Direction) -> List(Iodata) = - "string" "split" - -pub fn split(iodata, on) { - erl_split(iodata, on, All) -} - -external fn erl_replace(Iodata, String, String, Direction) -> Iodata = - "string" "replace" - -pub fn replace(iodata, pattern, replacement) { - erl_replace(iodata, pattern, replacement, All) -} - -pub external fn is_equal(Iodata, Iodata) -> Bool = "string" "equal" - -pub external fn is_empty(Iodata) -> Bool = "string" "is_empty" diff --git a/src/std/list.gleam b/src/std/list.gleam deleted file mode 100644 index 68dcb4a..0000000 --- a/src/std/list.gleam +++ /dev/null @@ -1,306 +0,0 @@ -import std/int -import std/order - -pub enum Empty = - | Empty - -pub enum NotFound = - | NotFound - -pub enum LengthMismatch = - | LengthMismatch - -// Using the Erlang C BIF implementation. -// -pub external fn length(List(a)) -> Int = "erlang" "length" - -// Using the Erlang C BIF implementation. -// -pub external fn reverse(List(a)) -> List(a) = "lists" "reverse" - -pub fn is_empty(list) { - list == [] -} - -pub fn contains(list, elem) { - case list { - | [] -> False - | [head | rest] -> head == elem || contains(rest, elem) - } -} - -pub fn head(list) { - case list { - | [] -> Error(Empty) - | [x | _] -> Ok(x) - } -} - -pub fn tail(list) { - case list { - | [] -> Error(Empty) - | [_ | xs] -> Ok(xs) - } -} - -fn do_filter(list, fun, acc) { - case list { - | [] -> reverse(acc) - | [x | xs] -> - let new_acc = - case fun(x) { - | True -> [x | acc] - | False -> acc - } - do_filter(xs, fun, new_acc) - } -} - -pub fn filter(list, fun) { - do_filter(list, fun, []) -} - -fn do_map(list, fun, acc) { - case list { - | [] -> reverse(acc) - | [x | xs] -> do_map(xs, fun, [fun(x) | acc]) - } -} - -pub fn map(list, fun) { - do_map(list, fun, []) -} - -fn do_index_map(list, fun, index, acc) { - case list { - | [] -> reverse(acc) - | [x | xs] -> do_index_map(xs, fun, index + 1, [fun(index, x) | acc]) - } -} - -pub fn index_map(list, fun) { - do_index_map(list, fun, 0, []) -} - -fn do_traverse(list, fun, acc) { - case list { - | [] -> Ok(reverse(acc)) - | [x | xs] -> - case fun(x) { - | Ok(y) -> do_traverse(xs, fun, [y | acc]) - | Error(error) -> Error(error) - } - } -} - -pub fn traverse(list, fun) { - do_traverse(list, fun, []) -} - -pub fn drop(list, n) { - case n <= 0 { - | True -> list - | False -> - case list { - | [] -> [] - | [_ | xs] -> drop(xs, n - 1) - } - } -} - -fn do_take(list, n, acc) { - case n <= 0 { - | True -> reverse(acc) - | False -> - case list { - | [] -> reverse(acc) - | [x | xs] -> do_take(xs, n - 1, [x | acc]) - } - } -} - -pub fn take(list, n) { - do_take(list, n, []) -} - -pub fn new() { - [] -} - -pub external fn append(List(a), List(a)) -> List(a) = "lists" "append"; - -fn do_flatten(lists, acc) { - case lists { - | [] -> acc - | [l | rest] -> do_flatten(rest, append(acc, l)) - } -} - -pub fn flatten(lists) { - do_flatten(lists, []) -} - -pub fn fold(list, acc, fun) { - case list { - | [] -> acc - | [x | rest] -> fold(rest, fun(x, acc), fun) - } -} - -pub fn fold_right(list, acc, fun) { - case list { - | [] -> acc - | [x | rest] -> fun(x, fold_right(rest, acc, fun)) - } -} - -pub fn find(haystack, f) { - case haystack { - | [] -> Error(NotFound) - | [x | rest] -> - case f(x) { - | Ok(x) -> Ok(x) - | _ -> find(rest, f) - } - } -} - -pub fn all(list, f) { - case list { - | [] -> True - | [x | rest] -> - case f(x) { - | True -> all(rest, f) - | _ -> False - } - } -} - -pub fn any(list, f) { - case list { - | [] -> False - | [ x | rest] -> - case f(x) { - | False -> any(rest, f) - | _ -> True - } - } -} - -pub fn zip(l1, l2) { - case {l1, l2} { - | {[], _} -> [] - | {_, []} -> [] - | {[x1 | rest1], [x2 | rest2] } -> [ {x1, x2} | zip(rest1, rest2) ] - } -} - -pub fn strict_zip(l1, l2) { - case length(l1) == length(l2) { - | True -> Ok(zip(l1, l2)) - | False -> Error(LengthMismatch) - } -} - -pub fn intersperse(list, elem) { - case list { - | [] -> [] - | [x | []] -> [x] - | [x | rest] -> [x | [elem | intersperse(rest, elem)]] - } -} - -pub fn at(list, i) { - case i < 0 { - | True -> Error(NotFound) - | False -> - case list { - | [] -> Error(NotFound) - | [x | rest] -> - case i == 0 { - | True -> Ok(x) - | False -> at(rest, i - 1) - } - } - } -} - -pub fn unique(list) { - case list { - | [] -> [] - | [x | rest] -> [x | unique(filter(rest, fn(y) { y != x }))] - } -} - -fn merge_sort(a, b) { - case {a, b} { - | {[], _} -> b - | {_, []} -> a - | {[ax | ar], [bx | br]} -> - case ax < bx { - | True -> [ax | merge_sort(ar, b)] - | False -> [bx | merge_sort(a, br)] - } - } -} - -pub fn sort(list) { - let list_length = length(list) - case list_length < 2 { - | True -> list - | False -> - let split_length = list_length / 2 - let a_list = take(list, split_length) - let b_list = drop(list, split_length) - merge_sort(sort(a_list), sort(b_list)) - } -} - -pub fn range(start, stop) { - case int:compare(start, stop) { - | order:Eq -> [] - | order:Gt -> [start | range(start - 1, stop)] - | order:Lt -> [start | range(start + 1, stop)] - } -} - -fn do_repeat(a, times, acc) { - case times <= 0 { - | True -> acc - | False -> do_repeat(a, times - 1, [a | acc]) - } -} - -pub fn repeat(a, times) { - do_repeat(a, times, []) -} - -fn do_split(list, n, taken) { - case n <= 0 { - | True -> {reverse(taken), list} - | False -> - case list { - | [] -> {reverse(taken), []} - | [x | xs] -> do_split(xs, n - 1, [x | taken]) - } - } -} - -pub fn split(list, n) { - do_split(list, n, []) -} - -fn do_split_while(list, f, acc) { - case list { - | [] -> {reverse(acc), []} - | [x | xs] -> - case f(x) { - | False -> {reverse(acc), list} - | _ -> do_split_while(xs, f, [x | acc]) - } - } -} - -pub fn split_while(list, f) { - do_split_while(list, f, []) -} diff --git a/src/std/map_dict.gleam b/src/std/map_dict.gleam deleted file mode 100644 index 32065f5..0000000 --- a/src/std/map_dict.gleam +++ /dev/null @@ -1,100 +0,0 @@ -import std/any -import std/result -import std/list - -pub external type MapDict(key, value); - -pub enum NotFound = - | NotFound - -pub external fn size(MapDict(k, v)) -> Int - = "maps" "size" - -pub external fn to_list(MapDict(key, value)) -> List({key, value}) - = "maps" "to_list" - -pub external fn from_list(List({key, value})) -> MapDict(key, value) - = "maps" "from_list" - -external fn is_key(key, MapDict(key, v)) -> Bool - = "maps" "is_key" - -pub fn has_key(map, key) { - is_key(key, map) -} - -pub external fn new() -> MapDict(key, value) - = "maps" "new" - -pub external fn fetch(MapDict(key, value), key) -> Result(value, NotFound) - = "gleam__stdlib" "map_fetch"; - -external fn erl_put(key, value, MapDict(key, value)) -> MapDict(key, value) - = "maps" "put"; - -pub fn put(map, key, value) { - erl_put(key, value, map) -} - -external fn erl_map_values(fn(key, value) -> value, MapDict(key, value)) - -> MapDict(key, value) - = "maps" "map"; - -pub fn map_values(map, fun) { - erl_map_values(fun, map) -} - -pub external fn keys(MapDict(keys, v)) -> List(keys) - = "maps" "keys" - -pub external fn values(MapDict(k, values)) -> List(values) - = "maps" "values" - -external fn erl_filter(fn(key, value) -> Bool, MapDict(key, value)) - -> MapDict(key, value) - = "maps" "filter"; - -pub fn filter(map, fun) { - erl_filter(fun, map) -} - -external fn erl_take(List(k), MapDict(k, v)) -> MapDict(k, v) = "maps" "with" - -pub fn take(map, keys) { - erl_take(keys, map) -} - -pub external fn merge(MapDict(k, v), MapDict(k, v)) -> MapDict(k, v) = "maps" "merge" - -external fn erl_delete(k, MapDict(k, v)) -> MapDict(k, v) = "maps" "remove" - -pub fn delete(map, key) { - erl_delete(key, map) -} - -pub fn drop(map, keys) { - list:fold(keys, map, fn(key, acc) { - delete(acc, key) - }) -} - -pub external type NotFound; - -pub fn update(dict, key, f) { - case fetch(dict, key) { - | Ok(value) -> put(dict, key, f(Ok(value))) - | Error(_) -> put(dict, key, f(Error(NotFound))) - } -} - -fn do_fold(list, acc, f) { - case list { - | [] -> acc - | [{k, v} | tail] -> do_fold(tail, f(k, v, acc), f) - } -} - -pub fn fold(dict, acc, f) { - let kvs = to_list(dict) - do_fold(kvs, acc, f) -} diff --git a/src/std/order.gleam b/src/std/order.gleam deleted file mode 100644 index 4d39705..0000000 --- a/src/std/order.gleam +++ /dev/null @@ -1,48 +0,0 @@ -pub enum Order = - | Lt - | Eq - | Gt -; - -pub fn reverse(order) { - case order { - | Lt -> Gt - | Eq -> Eq - | Gt -> Lt - } -} - -pub fn to_int(order) { - case order { - | Lt -> -1 - | Eq -> 0 - | Gt -> 1 - } -} - -pub fn compare(a, b) { - case {a, b} { - | {Lt, Lt} -> Eq - | {Lt, _} -> Lt - | {Eq, Eq} -> Eq - | {Gt, Gt} -> Eq - | {Eq, Gt} -> Lt - | _ -> Gt - } -} - -pub fn max(a, b) { - case {a, b} { - | {Gt, _} -> Gt - | {Eq, Lt} -> Eq - | _ -> b - } -} - -pub fn min(a, b) { - case {a, b} { - | {Lt, _} -> Lt - | {Eq, Gt} -> Eq - | _ -> b - } -} diff --git a/src/std/result.gleam b/src/std/result.gleam deleted file mode 100644 index 133d9d5..0000000 --- a/src/std/result.gleam +++ /dev/null @@ -1,51 +0,0 @@ -// Result represents the result of something that may succeed or fail. -// `Ok` means it was successful, `Error` means it failed. - -pub fn is_ok(result) { - case result { - | Error(_) -> False - | Ok(_) -> True - } -} - -pub fn is_error(result) { - case result { - | Ok(_) -> False - | Error(_) -> True - } -} - -pub fn map(result, fun) { - case result { - | Ok(x) -> Ok(fun(x)) - | Error(e) -> Error(e) - } -} - -pub fn map_error(result, fun) { - case result { - | Ok(_) -> result - | Error(error) -> Error(fun(error)) - } -} - -pub fn flatten(result) { - case result { - | Ok(x) -> x - | Error(error) -> Error(error) - } -} - -pub fn then(result, fun) { - case result { - | Ok(x) -> fun(x) - | Error(e) -> Error(e) - } -} - -pub fn unwrap(result, default) { - case result { - | Ok(v) -> v - | Error(_) -> default - } -} diff --git a/src/std/string.gleam b/src/std/string.gleam deleted file mode 100644 index 9eacb37..0000000 --- a/src/std/string.gleam +++ /dev/null @@ -1,36 +0,0 @@ -import std/iodata -import std/list - -pub external fn length(String) -> Int = "string" "length" - -pub enum ParseError = - | ParseError - -pub external fn lowercase(String) -> String = "string" "lowercase" - -pub external fn uppercase(String) -> String = "string" "uppercase" - -pub fn reverse(string) { - string - |> iodata:new - |> iodata:reverse - |> iodata:to_string -} - -pub fn split(string, on) { - string - |> iodata:new - |> iodata:split(_, on) - |> list:map(_, iodata:to_string) -} - -pub fn replace(string, pattern, with) { - string - |> iodata:new - |> iodata:replace(_, pattern, with) - |> iodata:to_string -} - -pub fn append(s1, s2) { - iodata:new(s1) |> iodata:append(_, s2) |> iodata:to_string(_) -} diff --git a/src/std/tuple.gleam b/src/std/tuple.gleam deleted file mode 100644 index ab38a74..0000000 --- a/src/std/tuple.gleam +++ /dev/null @@ -1,29 +0,0 @@ -import std/list - -pub fn new(a, b) { - {a, b} -} - -pub fn first(tup) { - let {a, _} = tup - a -} - -pub fn second(tup) { - let {_, a} = tup - a -} - -pub fn swap(tup) { - let {a, b} = tup - {b, a} -} - -pub fn fetch(haystack, needle) { - list:find(haystack, fn(tuple) { - case first(tuple) == needle { - | True -> tuple |> second |> Ok - | False -> Error([]) - } - }) -} -- cgit v1.2.3