Gleamことはじめ

2022/05/23に公開
2

概要

Gleamは、BEAM(Erlang VMとも言う)と呼ばれる仮想マシン上で動作するプログラミング言語です。
BEAM(ビーム)の韻を踏んで、読み方は「グリーム」です。

Gleamは、Rustで書かれています。
特徴として、型安全でスケーラブルなシステムを構築する用途を目指してます。
また、他のBEAM上で動作するプログラミング言語(たとえば、ErlangElixirLFE(Lisp Flavored Erlang))との親和性を有しています。

Gleamは、BEAM上で動作するのでErlangのバイナリ(beamファイル)をコンパイルします。
加えて、JavaScriptのコードも出力できます。

最新バージョンについて

Gleamは、2022年5月22日時点での最新バージョンは、「v0.21.0」です。
まだ、正式バージョンがリリースされていません。

正式バージョンのリリースを気長に待ちましょう。

https://github.com/gleam-lang/gleam/releases/tag/v0.21.0

追記!
2024年3月4日、待望の「v1.0.0」がリリースされました。

https://github.com/gleam-lang/gleam/releases/tag/v1.0.0
https://gleam.run/news/gleam-version-1/

PlayGroundでGleamを体験してみる

まずは、Gleamを体験してみます。

Gleam用のPlayGroundがあるので、こちらにアクセスします。

https://johndoneth.github.io/gleam-playground/

画面左部のエディタ部分には、初期値として以下のコードが書かれています。

import gleam/io

pub fn main() {
  io.print("hi")
  42
}

play_ground_01

画面上部の「Build&Run」をクリックしてみましょう。

画面右上部に実行結果が、画面右下部にコンパイル結果が出力されます。

play_ground_02

なお、現時点では「JavaScript」にチェックが付いているので、JavaScriptのコードがコンパイルされています。

では、「Erlang」を選択した場合はどうなるでしょうか。

play_ground_03

Erlang」を選択した場合、「Build&Run」は「Build」に変わります。
実行結果はブラウザ上で確認できません。
以下のようなメッセージが「Result」欄に出力されています。

Note that the Erlang target is not executable in the browser.

ただし、画面右下部にはコンパイル結果は出力されます。

play_ground_04

コードを修正してみる

PlayGroundでコードの動作確認ができたので、少し手を加えてみます。
なお、PlayGround上で動作確認もできるように、以降は「JavaScript」を選択して実行します。

コメントアウトする

コメントアウトには//を使います。

既存のコードio.print("hi")の先頭に//をつけると、コメントアウトされます。

import gleam/io

pub fn main() {
  //io.print("hi")
  42
}

Build&Run」をクリックすると、「Result」欄と「Compiled JavaScript」欄から、io.print("hi")に関する内容が消えています。

play_ground_02_01

変数へのバインディング

let 変数名 = 値で、変数に値をバインディングできます。
以下、let all_answer = 42let all_answerに「42」をバインディングします。

import gleam/io

pub fn main() {
  // io.print("hi")
  let all_answer = 42
  all_answer
}

play_ground_02_02

同じ変数名に再度バインディングするには、letが必要です。

また、Gleamでの値はすべてImmutableとなります。
そのため、別の変数へバイディング後に元の変数を再度バインディングして値を変更したとしても、値が変わるのは元の変数のみです。

以下の例では、all_answerへ42をバインディング後に、new_answerall_answerの値をバインディングしました。
その後、今度はall_answerへ43をバインディングしました。
プログラミング言語によっては、「代入」はオブジェクトへの参照だったり、アドレスの共有だったりします。この場合、元の値(all_answer)の値が変わると代入された側new_answerの値がall_answerの値と同じ(同じ場所を参照するため)になります。

しかし、Gleamにおける変数へのバインディングはImmutableであるので、設定時に不変の値として新しく生成されます。
そのため、let new_answer = all_answerとしても、new_answerall_answerはそれぞれ独立した42という値をもちます。
したがって、all_answerの値が変わっても、new_answerは影響を受けないのです。

pub fn main() {
  // io.print("hi")
  let all_answer = 42
  let new_answer = all_answer
  let all_answer = 43
  #(all_answer, new_answer)
}

play_ground_02_03

Intだとプリミティブ型のようにも思えるので、List型でも確認してみます。
List型の説明はまた後ほど。
実行してみると、やはりnew_answerは影響を受けていないことがわかります。

play_ground_02_04

文字列を扱う

Gleamの文字列は、「"」(ダブルクォーテーション)で括って表現します。
シングルクォーテーションは対応していません。

また、Gleamの文字列設定は、マルチラインに対応しています。「"」で囲んでいる中で改行を入れれば、文字列にも改行が含まれます。

なお、文字列同士を連結する場合には、標準ライブラリで提供されているappnedを利用します。appnedを利用するには、gleam/stringimportします。
そして、関数string.appendに対して、2つの文字列を格納した変数foobarを引数として渡します。

let baz = string.append(to: foo, suffix: bar)

これで、foobarの連結された文字列が、bazにバインディングされます。

import gleam/io
import gleam/string

pub fn main() {
  // io.print("hi")
  let foo = "The answer to the ultimate question"
  let bar = "about life,
    the universe,
    and all things"
  let baz = string.append(to: foo, suffix: bar)
  #(foo, bar, baz)
}

play_ground_02_05

数値を計算をしてみる

Gleamの数値の型には、Int(整数)とFloat(実数)があります。
これらの四則演算を実施してみましょう。

Intの場合、+で加算、-で減算、*で乗算、/で除算となります。

play_ground_02_06

一方でFloatの場合、+.で加算、-.で減算、*.で乗算、/.で除算となります。

play_ground_02_07

なお、IntFloatは、直接演算できません。
Floatをfloat.truncateを利用してIntに変換するか、
Intをint.to_floatFloatに変換するか
のどちらかをの対応が必要になります。

以下の例では、aではFloatからIntへの変換を、bではIntからFloatへの変換を実施しています。

import gleam/io
import gleam/float
import gleam/int

pub fn main() {
  let a = 40 + float.truncate(2.0)
  let b = 1_000.0 -. int.to_float(958)
  #(a, b)
}

play_ground_02_08

TapleとListを扱う

Gleamには、Taple型とListがあります。

Tapleは複数の型をまとめて、ひとつの型として設定したものになります。
たとえば、StringIntを組み合わせた場合、以下のように定義します。

#("Gleam導話", 1000)

Listは、あるひとつの型を複数個所持する配列のようなものになります。
たとえば、Intを複数持つ場合は以下のようになります。

[100, 200, 300, 400, 500]

また、Tapleを複数持つ場合は、以下となります。

[#("Gleam導話", 1000), #("Elixirへのいざない", 1500)]

ただし、Listに格納できるのは同じ型のみです。
違う型を格納しようとすると例外が発生します。

関数を作成する

Gleamでは、独自の関数を作成できます。
関数であることを示すfn 関数名で宣言し、引数には名前ど型、戻り値には型を指定します。
また、pubがあるとスコープが広がります。moduleを作成した場合、モジュール外部から呼び出せるようになるためです。

たとえば、Intの引数abを加算してIntの値を返す関数を作ると、以下となります。

pub fn add(a: Int, b: Int) -> Int {
  a + b
}

これをmain関数側から呼び出せば、この関数が実行されます。

import gleam/io

pub fn main() {
  let all_answer = add(40, 2)
  all_answer
}

pub fn add(a: Int, b: Int) -> Int {
  a + b
}

play_ground_02_09

今回のまとめ

GleamはBEAM上で動作するプログラミング言語です。
BEAMの特徴である並行性を持っているため、スケーラビリティに親和性を持っています。
さらに、型安全で作成されており、堅牢性にも配慮されております。
加えて、他のBEAM系の言語(ErlangやElixir)とも親和性を持っています。

一方で、残念ながらまだ正式バージョンのリリースが行われていません。
そのため、日の目をみることは当面先かと思われます。

2024年3月に正式版がリリースされました。
これによって、少しずつ実際のプロダクションなどでも事例が増えていくのではないかと予想されます。
※ただし、日本での事例は、もう少し後になるでしょうね。

また、v1になったことで、YouTubeでも動画を見かけるようになりました。再生回数もそれなりに多く感じます。

https://www.youtube.com/watch?v=_I-CSgoCgsk

https://www.youtube.com/watch?v=NyKIvWvr9kw

https://www.youtube.com/watch?v=9mfO821E7sE

Elixirの作者であるJosé Valim氏もスポンサーになっているため、可能性を秘めた言語であるともいえます。

来る日のために、Gleamを触ってみるのはいかがでしょうか。

参考情報

Discussion

tkztkz

興味深い記事の公開ありがとうございます。「PlayGroungでGleamを体験してみる」という見出しのtypoに気付いたのでお伝えしておきます。

MzRyuKaMzRyuKa

tkzさん

typeのご指摘、ありがとうございました。
修正しておきました。