Giter VIP home page Giter VIP logo

stdlib's Introduction

stdlib

GitHub release Discord chat CI

Gleam's standard library! Documentation available on HexDocs.

Installation

Add gleam_stdlib to your Gleam project.

gleam add gleam_stdlib

Usage

Import the modules you want to use and write some code!

import gleam/string

pub fn greet(name: String) -> String {
  string.concat(["Hello ", name, "!"])
}

Targets

Gleam's standard library supports both targets: Erlang and JavaScript.

Compatibility

This library is compatible with all versions of Erlang/OTP 26 and higher, as well as all NodeJS, Deno, Bun, and major browsers that are currently supported by their maintainers. If you have a compatibility issue with any platform open an issue and we'll see what we can do to help.

stdlib's People

Contributors

arothuis avatar aslilac avatar blond11516 avatar bsnyder788 avatar crowdhailer avatar cschembor3 avatar eterps avatar ethanppl avatar giacomocavalieri avatar inoas avatar jechol avatar lpil avatar majjoha avatar massivefermion avatar michael-mark-edu avatar michaeljones avatar michallepicki avatar quinnwilton avatar rawburt avatar richard-viney avatar rjdellecese avatar rvcas avatar schurhammer avatar scorpi4n avatar scripttease avatar sporto avatar tanklesxl avatar thehabbos007 avatar tranzystorekk avatar ustitc avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

stdlib's Issues

float.negate and int.negate

Int & Float negation is not recognised:

let num = 3
let neg = -num

gives unexpected token syntax error

you can get round it for now by:

let neg = 0 - num

list.key_set

Insert a value into a proplist, overwriting any existing value for that key.

iterator.take should return an iterator

The current functionality that iterator.take provides seems to be inconsistent with the idea of an iterator as a lazy structure.

If it returns an iterator instead, we would only have to call to_list as an additional step, but we could compose it with other iterators without consuming and evaluating.

Function currying

Hi, I am porting a validation lib I like to Gleam, the pattern used in this library relies heavily on one arity functions. e.g.

  Ok(<a function here that take one arg and returns another function>)
  |> validator.validate(user.name, validator.not_maybe)
  |> validator.validate(user.email, validator.not_maybe)
  |> validator.keep(user.age)

I don't think there is a build in way in Gleam to change fn(a, b, c) -> d to fn(a) -> fn(b) -> fn(c) -> d.
Is there?

So for the moment I am adding functions like this in the library:

pub fn map3(constructor: fn(a, b, c) -> value) {
  fn(a) {
    fn(b) {
      fn(c) {
        constructor(a, b, c)
      }
    }
  }
}

But maybe these make sense in the standard library e.g function.curry2, function.curry3 ...
Thanks

Math library/module

I have some interest in creating a math module/library for gleam. Would this be something which could reside in the stdlib? Or are there other libraries in gleam for this?

Or should certain things (i.e. abs, pow, sqrt, etc.) reside in the float/int modules?

Rename expect to should

output
|> expect.equal([1, 2, 3])
output
|> expect.true
output
|> expect.is_ok

Becomes

output
|> should.equal([1, 2, 3])

output
|> should.be_true

output
|> should.be_ok

Random function proposals

Hi
While doing advent of code I ended up with some functions I used often. Maybe some of these could be candiates for the standard library. Let me know if you like any and I can make PRs, thanks.

list.index_fold
Like fold, but also passing the index

list.try_fold
Like fold, but takes a function that returns Result(acc, acc).
If the result is Ok, it keeps folding, If Err it returns the acc immediately.
Useful when you want to stop folding early.

list.map2
Like map2 here https://package.elm-lang.org/packages/elm/core/latest/List#map2

list.rotate
Moves elements from one side of the list to the other.

E.g.

rotate([1,2,3,4,5], 2) == [3,4,5,1,2]

list.windows
Returns a list with tuples of contiguous elements.
Useful for doing operations that need to know the previous element.
E.g.
`windows([1,2,3,4,5]) == [(1,2), (2,3), (3,4), (4,5)]

int.to_binary

Converts an Int to a binary representation. I'm using Bool.
e.g. to_binary(12) == [True,True,False,False]
Would be better to have some binary literal however e.g. 0b1100

int.from_binary
The opposite of to_binary

result.replace_error
Many functions in the standard library return Result(a, Nil). But most of the time I want Result(a, error). So I ended up with a replace_error function. map_error is too verbose in this case.
e.g.

	input
	|> list.map(parse_line)
	|> result.all
	|> replace_error("Could not parse lines")

Thanks!

Add a system or os module

Reading through the elixir system module it seems to be a bit of a grab-bag of left over things. Some for talking to the operating system and some for returning information about the Elixir beam
situation.

At this point I'm really only requiring the ability to get env variables, it is working in my project but I was going to contribute it back to stdlib to kick off a system module.

I suspect for sometime this module will be a fairly thin wrapper around the erlang os module, so it might be best to name it after that. But I don't have strong opinions either way.

Error in docs about versions

file CHANGELOG.md
see incorrect highlighting at line 97 on screenshot.
reason: broken closing tick-char on line 94.

CudaText shows this.
Screenshot from 2021-01-18 23-11-11

orddict or proplists module in Gleam?

Given that maps are a bit restricted, and there is no map literal syntax (or plans for it), it seems like the orddict or proplists module from Erlang would make sense as a really primary data structure for arbitrary key/value pairs of mixed types.

It seems like there's some of this stuff in lists now, but since this is a specialized (and would be a highly used) form of list, I would think that making it its own module with different behavior (similar to Keyword in Elixir) might be helpful.

I'd be happy to implement these if y'all think this is a good idea.

Functions in uri to encode / decode parameters

Hi
I'm interested in making an opinionated query string parsing lib. Rails/jQuery style, where list are users[]=....

Could we have functions in uri to escape / unescape url strings?

Like encodeURIComponent and decodeURIComponent in JS. Eg.

encode("99% Great") -> "99%25%20Great"
decode("99%25%20Great") -> Just "99% Great"

I think that parse_query already does this. But standalone functions would be great.
Thanks

Math and Random numbers?

Quick question, are there math functions (e.g., abs, exp) or random number support in Gleam?

If not, could you please point me in the direction of documentation about erlang inter-op?

I'm new to BEAM and really excited about the Gleam project.

Should an iolist contains arbitrary binaries, not utf8 strings?

https://github.com/gleam-lang/stdlib/blob/master/src/gleam/iodata.gleam#L68

Should this function return a Binary not a string?

iex(7)> :erlang.iolist_size([0, 255, <<"abc">>])
5
iex(8)> :[email protected]_string([0, 255, <<"abc">>]) |> :[email protected]
** (ArgumentError) argument error: <<255, 97, 98, 99>>
    (stdlib 3.12.1) string.erl:728: :string.uppercase_bin/3
    (stdlib 3.12.1) string.erl:331: :string.uppercase/1

My expectation was that Iodata could be any binary. But that's coming from erlang/elixir semantics.

Change queue to/from list functions to direction preserving semantics

I was trying to use queue and end up quite confused. After a few operations my queue ended up in reverse order.
Not sure what is happening here. This test fails

	[1,2,3]
	|> queue.from_list
	|> queue.to_list
	|> should.equal([1,2,3])
 Failure/Error: ?assertEqual([1,2,3], Actual)
       expected: [1,2,3]
            got: [3,2,1]

dynamic.tuple1/2/3 etc

So this issue has the obvious question of where do you stop and for that reason it might be bad idea. However...

I have this code

      assert Ok(id) = dynamic.element(row, 0)
      assert Ok(id) = dynamic.int(id)
      assert Ok(topic) = dynamic.element(row, 1)
      assert Ok(topic) = dynamic.string(topic)
      assert Ok(note) = dynamic.element(row, 2)
      assert Ok(note) = dynamic.string(note)

Once you know a tuple has a 2nd element it must also have a 0th and 1st. therefore is the following simpler?

      assert Ok(tuple(id, topic, note)) = dynamic.tuple3(row)
      assert Ok(id) = dynamic.int(id)
      assert Ok(topic) = dynamic.string(topic)
      assert Ok(note) = dynamic.string(note)

Add result.lazy_unwrap

lazy_or(Result(a, e), fn() -> a) -> a

Return a fallback value generated from executing a function.

Either queue.push_front or queue.pop_front is not doing working correctly

I added this test

queue.new()
  |> queue.push_front(3)
  |> queue.push_front(2)
  |> queue.push_front(1)
  |> queue.pop_front()
  |> result.map(pair.first)
  |> should.equal(Ok(1))

So start with an empty queue and push several elements to the front.
The last element added at the front is 1.

When doing pop_front I would expect to get the 1 back.

 Failure/Error: ?assertEqual({ok,1}, Actual)
       expected: {ok,1}
            got: {ok,3}

Thanks

Bool and Result type documentation should list all possible constructors

Even though these types are a part of "the language" through Prelude, it would be nice to have the constructors printed in the documentation. For Bool, the documentation pretty clearly says there are only two possible values. For Result, things are not so obvious - Ok and Error are only mentioned without having them fully typed out: doc

I understand this may not be easily done, so maybe for now, link from the type doc to the Result type definition in The Gleam Book? And maybe it would be good enough.

string.starts_with and naming things

In the comment of the starts_with function in the string module it says 'Not sure about the name and labels here':

// TODO: Not sure about the name and labels here                     
// See if the second string starts with the first one.
//                                                           
// ## Examples
//    > starts_with(does: "theory", start_with: "ory")
//    False 

I can see why. Having a starts_with function with a labelled argument start_with seems a bit off.

From an end-user perpsective I can see pipeline usage like:

url |> string.starts_with(start_with: "https:")  // 1a
url |> string.starts_with("https:")  // 1b

IMHO 1a looks weird and confusing, 1b looks really good!

Or as regular function calls:

string.starts_with(does: url, start_with: "https:")  // 2a
string.starts_with(url, start_with: "https:")  // 2b
string.starts_with(url, "https:")  // 2c
string.starts_with(does: url, "https:")  // 2d

IMO 2a looks weird/confusing, 2b & 2c look a bit better, but not much. And 2d is an abomination.

The problem is the clear syntactic distinction between a function name and the parameter list in parentheses.

For example another option could be:

url |> string.starts(with: "https:")

It looks fine, but starts is not a very clear name for a function. Now it becomes dependent on the labelled argument being present.

I personally think that the function should be called starts_with and it should not have any optional argument labels because the absence of those labels seem to make the invocations more clear than with them.

url |> string.starts_with("https:")  // 1b

Let me know your thoughts.

Link to docs

When I google Gleam's standard library I get this repo.
But I would like to see the docs. Would be great to have a link to the docs from here.

list.chunk

Elixir has the chunk_* group of functions allowing one to group subsequences on Enum and Stream.

Another function I wanted but couldn't find is drop_while.

Can we have something similar on gleam lists and iterables?

Or if we already have, can someone point me to it?

Cannot surface errors in list.find_map

find_map is really useful, but the error is Nil returning no information of what failed.
When this fails to find I would like to have something in error to see what went wrong.

Could find_map return a list of errors instead of Nil?

pub fn find_map(
  in haystack: List(a),
  with fun: fn(a) -> Result(b, err),
) -> Result(b, List(err))

Thanks

dynamic.typed_map

The equivalent function as dynamic.typed_list but for maps.

mapping function should accept tuple(Dynamic, Dynamic) and return Result(t, String)

Note, this comes from an IRC conversation. I've elected to suggest this over a map.map function, as it was the problem I was having that day. I don't know if there want to also be an issue for map.map

Negative indexes

In the (TODO) doc comments of string.slice ( https://github.com/gleam-lang/stdlib/blob/master/src/gleam/string.gleam#L135 ), you see this example:

> slice("snakes on a plane!", from: -6, to: -1)
"plane"

Which surprises me because as a user of the slice function I would expect the function to be able to slice to the end of a string without having to know the length of that string beforehand.

So personally I expect to be able to do this:

> slice("freeby", from: -2, to: -1)
"by"

This is also how negative indexes work in Ruby for example (I'll have to check other languages though):

> "snakes on a plane!"[-6..-1]
=> "plane!"

Thoughts?

Add result.lazy_or

lazy_or(Result(a, e), fn() -> Result(a, e)) -> Result(a, e)

Return a fallback value generated from executing a function.

`erl_split` in gleam/iodata implementation issues

The definition of Erlang's string:split function is the following

split(String, SearchPattern, Where) -> [unicode:chardata()]
String = SearchPattern = unicode:chardata()
Where = direction() | all

And direction() is a type defined as

direction() = leading | trailing

Direction is used in several Erlang string functions, most applicable to us is string:replace which has a similar signature to string:split

We currently define a type Direction with the intention of mimicking this data type, but define it with one constructor: All, which isn't part of the data type. I understand this is part of an internal implementation. I would suggest the following:

  • Continue hiding this detail from consumers of the module
  • Add Leading and Trailing constructors to the Direction type
  • Add public functions that expose functionality of calling the erlang function with those atoms.

stdlib needs docs

I find it hard to get going learning gleam simply because the standard library is not documented. It would be better to have google searchable documentation hosted on hexdocs. As I'm coming from Elixir, I'm not very familiar with the erlang standard library either so I'm left looking at the standard library source code. While this works, it'd be much better with some example usages.

For now, I think the docs should be manually written. But I'd hope to see docs integrated with the language like Elixir has.

If I went and setup this project with docs to publish to hexdocs would you accept a PR for that?

Unable to import `gleam/string_builder`

Trying to import gleam/string_builder returns an error during compilation. Error message as follows:

error: Unknown import
   โ”Œโ”€ /home/hhandoko/.../kattis_gleam/src/kattis_gleam/timeloop.gleam:66:8
   โ”‚
66 โ”‚ import gleam/string_builder
   โ”‚        ^^^^^^^^^^^^^^^^^^^^ did you mean `gleam/string`?

The module `kattis_gleam/timeloop` is trying to import the module `gleam/string_builder`,
but it cannot be found.

Repo and branch to replicate the issue can be found here: https://github.com/hhandoko/kattis_gleam/tree/bugfix/string_builder_import

Line of code where the import is added: https://github.com/hhandoko/kattis_gleam/blob/bugfix/string_builder_import/src/kattis_gleam/timeloop.gleam#L66

Links:

string.drop_before

Proposal

Add an index_of function to the gleam stdlib for strings. We have a contains function already, but it may also be useful to have the ability to see where in a string a certain substring occurs, similar to erlang's str/rstr.

It could be something like:

let input = "testing"
input
  |> string.index_of("e")
  |> should.equal(1)

input
  |> string.index_of("erlang")
  |> should.equal(-1)

list.unzip

The opposite of list.zip, I don't think it exists already but I guess it might have a different name

Should have fn signature pub fn zip(List(tuple(a, b))) -> tuple(List(a), List(b)

queue incompatible with erlang queue.

Converting list to queue, then convert back to list returns same list in Erlang.
Can we replace custom implementation with Erlang's?

1> gleam@queue:to_list(gleam@queue:from_list([1,2,3])).  
[3,2,1]
2> queue:to_list(queue:from_list([1,2,3])).
[1,2,3]

I think is_logically_equal is pointless that we can remove it.

If you agree with this, I can do this.

dynamic.option function

This comes up a lot when decoding json.

  assert Ok(name) = dynamic.field(data, "name")
  let name = case dynamic.string(name) {
    Ok(name) -> Some(name)
    // Assumes it's nil
    _ -> None
  }

Something like the following might be helpful

assert Ok(name) = dynamic.field(data, "name")
assert Ok(name) = dynamic.option(name, dynamic.string)

Running the tests / adding modules?

Hi, I'm adding a Date library. I've added this file to src/gleam/date.gleam

/// Functions and types relating to dates.
/// Defaults to UTC, which is the only supported timezone at this time.
///
/// Years cannot be abreviated.  Years start from 0 and go up.  So if the year = 93,
/// it does not refer to 1993.  This is in line with the behavior of Erlang.
///
pub type Year {
  Year(year: Int)
}

pub type Month {
  Month(month: Int)
}

pub type Day {
  Day(day: Day)
}

pub type Date {
  Date(year: Year, month: Month, day: Day)
}

/// Safely create a valid Date.
///
/// ## Examples
/// ```gleam
/// new(2020, 04, 20) == Ok(Date((Year(2020), Month(04), Day(20)))
/// new(-1, -1, -1) == Error("Parameters are invalid for a date.")
/// ```
///
pub fn new(year: Year, month: Month, day: Day) -> Result(Date, String) {
  case is_valid_date(year, month, day) {
    True -> Ok(Date(day, month, year))
    False -> Error("Parameters are invalid for a date.")
  }
}

/// Gets the current Date.
///
/// ## Example
///
/// ```gleam
/// current_date == Date(Year(2020), Month(04), Day(22))
/// ```
///
pub fn current_date() -> Date() {
  tuple(tuple(year, month, day), tuple(_, _, _)) = "calendar" "universal_time"
  Date(year, month, day)
}

And added this test to test/gleam/date.gleam

/// Functions and types relating to dates.
/// Defaults to UTC, which is the only supported timezone at this time.
///
/// Years cannot be abreviated.  Years start from 0 and go up.  So if the year = 93,
/// it does not refer to 1993.  This is in line with the behavior of Erlang.
///
pub type Year {
  Year(year: Int)
}

pub type Month {
  Month(month: Int)
}

pub type Day {
  Day(day: Day)
}

pub type Date {
  Date(year: Year, month: Int, day: Int)
}

/// Safely create a valid Date.
///
/// ## Examples
/// ```gleam
/// new(2020, 04, 20) == Ok(Date((Year(2020), Month(04), Day(20)))
/// new(-1, -1, -1) == Error("Parameters are invalid for a date.")
/// ```
///
pub fn new(year: Year, month: Month, day: Day) -> Result(Date, String) {
  case is_valid_date(year, month, day) {
    True -> Ok(Date(day, month, year))
    False -> Error("Parameters are invalid for a date.")
  }
}

/// Gets the current Date.
///
/// ## Example
///
/// ```gleam
/// current_date == Date(Year(2020), Month(04), Day(22))
/// ```
///
pub fn current_date() -> Date() {
  tuple(tuple(year, month, day), tuple(_, _, _)) = "calendar" "universal_time"
  Date(year, month, day)
}

But I don't see the module in the gen directory.

Also how is the test suite ran?

Think this language look interesting!

Inconsistency between dynamic.list and dynamic.map

dynamic.list requires a mapping function and dynamic.map doesn't
In the map case the result is assumed to be of type Map(Dynamic, Dynamic)
Could there be a dynamic.list function that just returned the type List(Dynamic)

Potentially both map and list could have variants that accepted a mapper, e.g. dynamic.list_cast and dynamic.map_cast

Expose `identity` and `always` functions?

fn identity(a: a) -> a { a }

fn always(a: a, b: b) -> b { b }

I've just run across a scenario where an always function (like the one defined above) would have been useful to have, and identity is a close sibling that can be useful too. Should they be added to the standard library? If so, where would they go?

gleam/os add timestamp function

make use of external "os" "timestamp"

This function returns a tuple and we probably want to map it to a record like so:

pub type Timestamp {
  Timestamp(
    mega_seconds: Int,
    seconds: Int,
    micro_seconds: Int,
  )
}

So we can do timestamp.seconds:

Signature

timestamp : () -> Timestamp

Is Any a good name?

Currently we have an Any type which is a strong way of representing dynamically typed data.

Is Any a good name, or is it misleading?

  • In PureScript it is called Foreign
  • In Rust it is called Any
  • In Haskell it is called Dynamic

At the moment I'm leaning towards changing Gleam to use Dynamic

queue.push_back doesn't push back

Using push_back puts an element in the front of the queue, not the back as expected

let expected = [1,2,3] |> queue.from_list

	[1,2]
	|> queue.from_list
	|> queue.push_back(3)
	|> should.equal(expected)`
     Failure/Error: ?assertEqual({queue,[1,2,3],[]}, Actual)
       expected: {queue,[1,2,3],[]}
            got: {queue,[3,1,2],[]}

Int & float - clamp

Elm has a function called clamp in its standard library, which I have often found quite useful to restrict a number within an upper and lower bound. We could implement it in Gleam something like this:

pub fn clamp(x: Int, bound1: Int, bound2: Int) -> Int {
  let lower_bound = min(bound1, bound2)
  let upper_bound = max(bound1, bound2)
  x
  |> min(upper_bound)
  |> max(lower_bound)
}

(And similarly for floats.)

This reminds me that there was also some discussion in the Elm community about naming for min and max. When they're used in pipelines (as in the example above), it's easy to be confused and get the opposite of the behaviour you want. The intention becomes clearer if you use aliases like at_most and at_least:

pub fn at_most(x: Int, upper_bound: Int) -> Int {
  min(x, upper_bound)
}

pub fn at_least(x: Int, lower_bound: Int) -> Int {
  max(x, lower_bound)
}

pub fn clamp(x: Int, bound1: Int, bound2: Int) -> Int {
  let lower_bound = min(bound1, bound2)
  let upper_bound = max(bound1, bound2)
  x
  |> at_most(upper_bound)
  |> at_least(lower_bound)
}

But I can also appreciate that it might be better not to bloat the stdlib with aliases for functions that already exist, or that users can easily implement for themselves. I guess it all depends on Gleam's philosophy.

If you think it is worth implementing one or all of these functions, I could have a go at a pull request.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.