Logo

dev-resources.site

for different kinds of informations.

Hands-On with Gleam: Building and Improving a Binary Search Tree

Published at
6/16/2024
Categories
patternmatching
gleam
functional
erlang
Author
micskeil
Author
8 person written this
micskeil
open
Hands-On with Gleam: Building and Improving a Binary Search Tree

Gleam is a functional programming language that proudly aims to be simple. This means you have a few straightforward tools to solve problems. That's why it's such a great language for zoning out from other perspectives and allowing you to solve coding problems differently than you are used to.

Let's zone out. Build a binary search tree and see how we can improve the code step by step, and what we can learn from it.

Binary search trees perform better than arrays when inserting or retrieving sortable data. They are built from nodes, with each node containing data and two pointers to other nodes. The left node has a value smaller than or equal to the value stored in the current node, while the right node stores a value larger than that stored in the current node.

In Gleam you can write a type to represent this:

pub type Tree {
  Node(data: Int, left: Tree, right: Tree)
  Nil
}
Enter fullscreen mode Exit fullscreen mode

In Gleam, we can use pattern matching and the 'case' expression to add new data to the tree. My first attempt at writing a function to add a new node to a tree was as follows:

fn add_to_tree(tree: Tree, data: Int) -> Tree {
  case tree {
    Node(tree_data, Nil, right) if data <= tree_data -> {
      Node(tree_data, Node(data, Nil, Nil), right)
    }
    Node(tree_data, left, Nil) if data > tree_data -> {
      Node(tree_data, left, Node(data, Nil, Nil))
    }
    Node(tree_data, left, right) if data <= tree_data -> {
      Node(tree_data, add_to_tree(left, data), right)
    }
    Node(tree_data, left, right) if data > tree_data -> {
      Node(tree_data, left, add_to_tree(right, data))
    }
    Nil -> Node(data, Nil, Nil)
    _ -> panic as "Invalid tree"
  }
}
Enter fullscreen mode Exit fullscreen mode

A few things might bother you with this code. Primarily, the last branch shouldn't be needed. However, since Gleam doesn't try to evaluate any complex pattern with 'if', the code won't compile without that last branch, even though we know it is impossible for the data to take that route.

Nest a little bit.

Nest a little bit.
Coming from JavaScript, where "nevernesting" is a principle, it might feel unnatural, but in Gleam, we can sometimes nest and benefit from it. First, let's move the comparison one nested level down.

I've included a picture from my editor of this refactor to illustrate how easy and nice it is, thanks to the Gleam language server.

Image description

Let's delete those lines marked unreachable.

fn add_to_tree(tree: Tree, data: Int) -> Tree {
  case tree {
    Node(tree_data, left, right) -> {
      case data <= tree_data {
        True -> Node(tree_data, add_to_tree(left, data), right)
        False -> Node(tree_data, left, add_to_tree(right, data))
      }
    }
    Nil -> Node(data, Nil, Nil)
  }
}
Enter fullscreen mode Exit fullscreen mode

Much better. Notice how we moved the real work inserting the data to the Nil case, it means our recursive function now only has one base case and one for deciding the direction in the tree. The last optimization can be to put the base case in the first position, but I will let you do that.

In summary, by leveraging Gleam's simplicity and powerful pattern matching, we streamlined our binary search tree implementation. We reduced complexity and made the code more intuitive, enhancing readability and maintainability. With each step, we learned to harness Gleam's features to write cleaner, more efficient code. Happy coding!

erlang Article's
30 articles in total
Favicon
Elixir em Foco em 2024
Favicon
Parsing Grid-Based STDIN Input in Gleam
Favicon
Bridging the Gap: Simplifying Live Component Invocation in Phoenix LiveView
Favicon
RabbitMQ with Web MQTT Plugin vs. Node.js : Performance and Memory Usage Comparison
Favicon
Navigating the EEF Stipend Process
Favicon
👉 What is gleam language used for ❓
Favicon
Implementing OpenID Connect on the BEAM
Favicon
OpenID Connect—An Introduction
Favicon
Por que o Elixir Ă© melhor que Node.js para Processamento AssĂ­ncrono?
Favicon
How To Deploy RabbitMQ On Public IP?
Favicon
Weather API: A GenServer and LiveView Implementation Part I
Favicon
Berkenalan Dengan Bahasa Pemrograman Fungsional Elixir (Bagian 1)
Favicon
(Amazing!) How to manage and install multiple versions of Erlang/OTP and Elixir via vfox in Windows
Favicon
Hands-On with Gleam: Building and Improving a Binary Search Tree
Favicon
Historia de la BeamVM
Favicon
Elixir Days - Evento presencial em SĂŁo Paulo
Favicon
BEAM VM The good, the bad and the ugly
Favicon
ConferĂŞncias do Ecossistema de Erlang (e Elixir)
Favicon
Deep Diving Into the Erlang Scheduler
Favicon
Install mutiple Erlang and Elixir with vfox
Favicon
Installing Erlang With vfox
Favicon
Erlang Workshop 2024 - Call for Papers
Favicon
Empresas brasileiras que usam, ou usaram, Elixir ou Erlang
Favicon
Binary Data in Gleam: Implementing The RCON Protocol
Favicon
Using the Keyword module for options
Favicon
How to take leverage from on_mount to reduce code
Favicon
What you should know about the live_session macro
Favicon
Build Phoenix Docker Compose development environment easily
Favicon
When to use the handle_params callback
Favicon
The “let it crash” error handling strategy of Erlang, by Joe Armstrong

Featured ones: