gleam programming language


If you’ve never seen gleam code, it looks something like this. The example is taken from the standard library. The standard library, by the way, is quite complete, but not yet fully documented. Therefore, if you want to use it, you have to look at the source code a bit.

The syntax is probably closest to Rust. There are all the charms of functional programming: for example, there is no return construct.

The code is divided into modules and functions. Modules correspond to source files, with an intuitive import syntax. In this it differs from, say, the Elixir language, where physical and logical modules are not the same thing. In addition, in the elixir, modules correspond to data structures (struct), which introduces even more confusion.

The language is pretty minimalistic. For example, it lacks for And if. There is also no syntax for dictionaries, so pattern matching cannot be done for them either. Those interested can read The Gleam Book to find out what is in gleam and what is not.

Also, there are no “atoms” in gleam. Erlang uses atoms as constants. For example, on success, a function might return an atom okand if not successful – error. gleam uses types for this purpose. Atoms cannot be created directly in gleam, if you want to use an atom, create a new type. The solution is original and I really like it. For example, for the mentioned case it looks like this:

let parsed = case parse_int("123") {
  Error(e) -> io.println("That wasn't an Int")
  Ok(num) -> num
}

By the way, about mistakes. There is no construction in gleam try..catch (which is in erlang). Instead, it is recommended to use the Rust-like approach above. In general, there is a “let it crash” principle in erlang that does not recommend catching exceptions, instead allowing the process in which the exception was thrown to crash. In principle, we can say that gleam follows the recommendations, because in principle there is no possibility of catching an exception in it.

Functions are private by default. To make a function public, you need to specify a modifier for it pub. Suitable for people who do not seek publicity. There is also a simple and clear way to declare constants at the module level using the word const.

There is another interesting design use, which probably has no analogues in other languages. The author describes it as syntactic sugar for wrapper functions. Only on steroids. And gives an example

pub fn main() {
  use <- logger.record_timing
  use db <- database.connect
  use f <- file.open("file.txt")
  // Do with something here...
}

This is equivalent to the following code

pub fn main() {
  logger.record_timing(fn() {
    database.connect(fn(db) {
      file.open("file.txt", fn(f) {
        // Do with something here...
      })
    })
  })
}

In particular, this is one way to solve the callbacks hell problem.

Well and, of course, it is necessary to tell separately about types. They are optional in gleam, you don’t have to declare them. You can annotate any expression with a type. Custom types are declared like this

type User {
  LoggedIn(name: String)  // A logged in user with a name
  Guest                   // A guest user with no details
}

As you can see, you can declare multiple types within a single type block. But – it is possible and one. You can use them later like this

fn get_name(user) {
  case user {
    LoggedIn(name) -> name
    Guest -> "Guest user"
  }
}

That is, types are used both for pattern-matching and for static analysis. There are also restrictions that gleam imposes on data structures: lists and dictionaries cannot have values ​​of different types. The compiler forbids.

About these last restrictions – I think there is no real need for them, and they are rather controversial. Well, I would issue a warning, and the final decision would be up to the programmer. After all, erlang itself is not typed, and the type annotation is optional – the compiler may simply not have all the necessary information.

gleam does a source-to-source conversion of its code to Erlang code when it is built. It is written in Rust.

Well, that’s all I wanted to tell you about the gleam language. There is a poll at the end. A picky reader may not read further, because further proposals will be maximally non-specific and maximally inappropriate.

In general, studying the possibilities of gleam, I caught myself thinking that they are completely covered by the python syntax (I am a python programmer). Well, or almost entirely: there is no pipeline operator in python (this: |>).

So, I thought that if some, not quite adequate, person decides to remake gleam for Python syntax, then he will not encounter any difficulties along the way. Of course, such a person would use the gleam compiler to generate Erlang code.

Is this possible, and how different is an imperative language from a functional one?

In version 3.10, python added match..case with a rather sprawling syntax: with types, conditions and everything that could be added. It looks like this:

match user:
  case LoggedIn(name):
    # serve user
  case Guest():
    # serve guest

Does he fit? Not really. There is a small problem: match must be an expression, must return a value. That is, it must be

result = match user:
  # и дальше по тексту

The same goes for other keywords: if, for, try. Only if the block match stands last in the function, its current syntax is fine.

You can forget about classes and the whole OOP (and you should). Classes should only be used for type annotation. Otherwise, the vanilla Python syntax is completely self-sufficient. You can take a parser for python and parse code with it.

But it doesn’t happen that someone has the opportunity to add more syntax, and he did not. If this happens in our case, what will it be? Here are the options.

1) Pipeline operator (|>)

It looks very good in code. Most useful at the end of match, if, for statements:

result = match obj:
  case {'data': data}: data
|> process_data()
|> process_more()

Also, the match block itself can stand after the pipeline operator:

result = match obj:
  # что-то
|> match:
  # ещё что-то

In other cases, it is less needed, but of course, why not use it in ordinary expressions as well.

2) Anonymous functions

There are lambdas in python, but they are defective. The full ones would look like this:

f = def(x, y):
  x + y

In fact, this is the same as declaring a function in the usual way. But lambda can be used after the pipeline operator:

result = match value:
  # что-то
|> def(x):
  # что-то на выходе

3) Pattern matching on assignment operations

MyType(data) = obj

It’s convenient to have this option. Syntax is the same as in part case at match.

Thus, it is safe to conclude that gleam could very well have python syntax. I hope I have satisfied your curiosity in terms of how this could be, and convinced that the syntax of the python is really rich.

What do you say?

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *