I tried Gleam for Advent of Code

2025/12/14 2:00

I tried Gleam for Advent of Code

RSS: https://news.ycombinator.com/rss

要約

Japanese Translation:

改訂サマリー:
著者は、7 年連続で Advent of Code のすべてのチャレンジを解決した経験を語り、2025 年に Gleam を選んだ理由を説明しています。彼らは 2025 年が 12 日(24 部)に短縮されたことにも触れています。Gleam のクリーンな構文、便利なコンパイラ診断、

echo
dict.get
などの組み込みヘルパー、関数型スタイル、スムーズな言語サーバーが効率的で楽しい体験に貢献しました。しかし、標準ライブラリにはファイル I/O と正規表現がなく、外部依存 (
simplifile
gleam_regexp
) が必要です。また、パターンマッチは中間要素と末尾要素を同時に持つリストを分解できず、一部の解析戦略に制限がありました。著者はまた、すべてのターゲットで統一された大整数処理を望んでいます。これらの長所と短所を強調することで、他の Advent of Code 参加者や開発者に Gleam を試し、その成長するエコシステムに貢献してもらうことを期待しています。

本文

毎年アドベント・オブ・コード(AoC)に挑戦しています。
過去七年間、今年を含めて全ステージの星を獲得できました。
自慢したいわけではなく、そう言うのは「なぜまた戻ってくるか」を説明するためです。
長時間続けても飽きない数少ない技術的伝統の一つであり、
締め切りがある緊張感やコミュニティの雰囲気、毎年12月に好きな言語を選んで没頭できる点が好きです。

今年は Gleam を選びました。


1 年間を短縮した構成

通常 AoC は 25 日間ですが、今年は Eric が 12 日間にしてくれたので、パート数は 50 から 24 に減りました。
「リラックスできる年」には思えましたが、実際は逆に早いペースで進むことになり、
以前よりも難しい日が多かったのですが、それでも楽しく取り組めました。
また、最初から 50 パートをこなすとツールボックスを作る余裕があるのに対し、
12 日間では パズルがまだ構築途中のツールボックスを要求してくるので、新しい言語学習にピッタリでした。


2 Gleam が AoC に合う理由

Gleam はすぐに好きになれる

シンタックスはきれいで、コンパイラが親切。エラーも抜群です。
Rust ほどではありませんが、言語自体が「テキストを解析 → 処理を重ねる → 集約する」という AoC に合ったスタイルへと自然に誘導します。
さらに パイプ が至る所にあるので好きです。

エディタ体験が予想以上に良い

LSP は思ったよりもずっとスムーズで、IntelliJ の Gleam 拡張機能は完璧でした。
https://plugins.jetbrains.com/plugin/25254-gleam-language

関数型プログラミングが好き

FP は必ずしも簡単ではありませんが、理解できれば「手順を書かない」形で解決策を記述できます。


3 Gleam のスーパー機能:
echo

最初に惹きつけられたのは

echo

値をそのままパイプラインへ渡して表示できる プリント 文です。

list.range(0, 5)
|> echo
|> list.map(int.to_string)
|> echo

複数箇所で値を確認したいときに、流れを壊さずに済みます。
文字列補間がなくても、

echo
が多くの場面で足りました。
例として LP ファイル(
glpsol
用)を作るコード:

"Minimize\n"
<> "  total: "
<> buttons
|> string.join(" + ")
<> "\n\nSubject To\n"

4 グリッドパズルに便利な「オプション」

多くの AoC パズルはグリッドを扱います。

dict.get
Option
を返すので、境界チェックが不要です。

fn get_neighbours(grid: Grid(Object), pos: Position) -> List(Object) {
  [
    #(pos.0 - 1, pos.1 - 1),
    #(pos.0 - 1, pos.1),
    #(pos.0 - 1, pos.1 + 1),
    #(pos.0, pos.1 - 1),
    #(pos.0, pos.1 + 1),
    #(pos.0 + 1, pos.1 - 1),
    #(pos.0 + 1, pos.1),
    #(pos.0 + 1, pos.1 + 1),
  ]
  |> list.filter_map(fn(neighbour_pos) { grid |> dict.get(neighbour_pos) })
}

また

list.transpose
があれば Day 6‑part 1 は転置だけで解けました。
Gleam に備わっている関数が多く、
list.combination_pairs
なども便利です。


5 「fold_until」こそ好きな機能

「早期終了」を安全に行える

fold_until
は、パズルで頻出する 条件付き集約 に最適です。
例:Day 8‑part 2 の集合マージ。

|> list.fold_until(initial, fn(acc, pair) {
  case done_yet {
    True -> Stop(new_acc)
    False -> Continue(new_acc)
  }
})

6 Gleam がちょっと手間だった点

  • 標準ライブラリにファイル I/O がない
    Day 1 で驚きました。

    simplifile
    を使いましたが、基本的には外部依存です。

  • 正規表現も別パッケージ
    Day 2‑part 2 では

    gleam_regexp
    を追加し、次のように書きます。

let assert Ok(re) = regexp.from_string("^(" <> substring <> ")+$")
regexp.check(re, val)
  • リストパターンマッチングの制限

    [first, ..rest]
    [first, second]
    は書けるが、
    [first, ..middle, last]
    は不可。
    パースをシンプルにしたいときは不便。

  • 比較は明示的
    比較演算子は

    bool
    ではなく順序値です。
    <=
    を書くと少し冗長になります。

    case cmp_start, cmp_end {
      order.Lt, _ -> False
      _, order.Gt -> False
      _, _ -> True
    }
    
  • ビッグ整数と JavaScript 対応

    bigi
    を使うケースが出てきました。Erlang VM ではオーバーフローは起きませんが、
    JavaScript ターゲットだと必要になるため、
    Int
    に統一できれば便利です。


7 XOR とビットマスクの魅力

Day 10‑part 1 が最も好き。
ライトを数値で表し、ボタンはビットマスクとして扱い、XOR で最小組み合わせを求めました。

combination
|> list.fold(0, fn(acc, comb) {
  int.bitwise_exclusive_or(acc, comb)
})

シンプルで高速。表現が多くの作業を担ってくれます。


8 glpsol を呼び出す手間

Day 10‑part 2 は逆に「外部コマンド」を使う必要がありました。

shellout.command("glpsol", ["--lp","temp.lp","-w","temp_sol.txt"], ".", [])
で動き、
LP フォーマット自体は美しかったです。


9 実際に役立つメモ化キー

Day 11‑part 2 のメモ化では「ノード+状態」をキーにしました。

#(neighbour, new_seen_dac, new_seen_fft)

正しくスレッドを作ると、即座に高速化できました。


10 最後のパズル:トロール問題

最後の日は “入力に対して想定外の動きがある” と感じました。
「完全に組み合わさったピースの面積がボードに収まるか」をヒューリスティックで判断しました。

heuristic_area <= max_area

11 終わりに

Gleam を選んだことを本当にうれしく思います。
標準ライブラリの限界はあるものの、パイプラインや

Option
Result
が安全性を高め、
list
関数群や
fold_until
は驚きでした。
ループを書かずに関数型で書けると、解法がより明確になります。

実際のプロジェクトでも Gleam を使いたいです。ウェブサーバーを作る予定で、今からワクワクしています。来年の AoC も待ちきれません。

すべて 12 日分のソースはここにあります:
https://github.com/tymscar/Advent-Of-Code/tree/master/2025/gleam/aoc/src

同じ日のほかのニュース

一覧に戻る →

2025/12/14 7:58

Linux Sandboxes and Fil-C

## Japanese Translation: メモリ安全性とサンドボックスはプログラムの異なる部分を保護するため、両方が強力なセキュリティに必要です。純粋な Java プログラムはメモリ安全であってもファイルシステムの syscalls を通じて任意のファイルを書き込むことができるし、逆にすべての能力を取り消したアセンブリプログラムでもメモリバグがある場合がありますが、カーネルが特権 syscalls を殺すためサンドボックスから逃げられません。サンドボックスは意図的に許容範囲を広く設計しているため、攻撃者は残されたメモリ安全性のバグを利用してブローカー・プロセスへ到達することができるので、両方の防御を組み合わせるとより強固な保護が得られます。 本書では、C/C++ 用に設計され、システムコールまで安全性を保証し、init や udevd などの低レベルコンポーネントで使用できるメモリ安全ランタイム「Fil‑C」への OpenSSH の seccomp ベース Linux サンドボックス移植方法について説明します。OpenSSH は既に chroot を採用し、`sshd` ユーザー/グループとして特権なしで実行し、`setrlimit` を使用し、非許可 syscalls を `SECCOMP_RET_KILL_PROCESS` で殺す seccomp‑BPF フィルタを適用しています。Fil‑C はその runtime 内で自動的にこれらの syscalls を許可することで簡素化します。背景スレッドは存続させつつスレッド生成を防ぐため、Fil‑C は API `void zlock_runtime_threads(void)` を追加し、必要なスレッドを事前確保してシャットダウンを無効にします。 OpenSSH の seccomp フィルタは強化されています。失敗時の挙動が `SECCOMP_RET_KILL` から `SECCOMP_RET_KILL_PROCESS` に変更され、mmap 許可リストに新たに `MAP_NORESERVE` フラグが追加され、`sched_yield` が許可されています。サンドボックスは二つの `prctl` コール(`PR_SET_NO_NEW_PRIVS` と `PR_SET_SECCOMP`)で構築され、エラー検出も行われます。Fil‑C のランタイムは `filc_runtime_threads_handshake` で全スレッドとハンドシェイクし、各スレッドが no_new_privs ビットと seccomp フィルタを持つことを保証します。複数のユーザー スレッドが検出された場合、安全エラーが発生します。 メモリ安全性とサンドボックスを組み合わせることで、OpenSSH はより厳格な隔離を実現し、メモリバグによる権限昇格リスクを低減します。このアプローチは他のセキュリティクリティカルプロジェクトにも採用を促す可能性があります。

2025/12/14 9:34

An Implementation of J

## Japanese Translation: ## 改訂版要約 本書は、技術仕様の構造化された目次であり、以下のように整理されています。 1. **第0章 – はじめに** 2. **第1章 – 文を解釈する** - 1.1 単語生成 - 1.2 構文解析 - 1.3 トレイン(列車) - 1.4 名前解決 3. **第2章 – 名詞** - 2.1 配列 - 2.2 型 - 2.3 メモリ管理 - 2.4 グローバル変数 4. **第3章 – 動詞** - 3.1 動詞の構造 - 3.2 ランク - 3.3 原子(スカラー)動詞 - 3.4 オブヴァース、同一性、および変種 - 3.5 エラー処理 5. **第4章 – 副詞と接続詞** 6. **第5章 – 表現** - 5.1 原子表現 - 5.2 ボックス化された表現 - 5.3 木構造表現 - 5.4 線形表現 7. **第6章 – ディスプレイ** - 6.1 数値表示 - 6.2 ボックス化表示 - 6.3 フォーマット済み表示 主要セクションの後に、付録A〜F(インキュナブルム、スペシャルコード、テストスクリプト、プログラムファイル、外国接続詞、およびシステム概要)が補足資料として提供されます。書末には参考文献・用語集・索引が付されています。 この構成(目次 → 詳細セクション → 付録 → 参照資料)は、読者に全体枠組みを最初に把握させたうえで、必要に応じて詳細へ掘り下げたり補足資料を参照したりできる明確かつ階層的な道筋を提供します。

2025/12/14 8:39

Closures as Win32 Window Procedures

## Japanese Translation: **改訂版要約:** この記事では、Win32 のウィンドウプロシージャに追加のコンテキストポインタを渡す方法を示しています。これは、WndProc が通常 4 つしか引数を取らないため、ネイティブ API には備わっていない機能です。著者は x64 アセンブラで小さなトランスペイル(trampoline)を作成し、実行時に JIT コンパイルして 5 番目の引数スロットを挿入し、呼び出し前に必要なコンテキストを格納します。これにより、各ウィンドウがグローバル変数や `GWLP_USERDATA` を使わずに独自の状態を保持できるようになります。トランスペイルは GNU アセンブラで書かれ、`.exebuf` セクション(`bwx` フラグ付き)から 2 MiB の実行可能バッファが確保されます。C ヘルパー関数 `make_wndproc(Arena *, Wndproc5, void *arg)` は 2 つのバイトオフセットプレースホルダーを修正してトランスペイルを生成します。作成後は `set_wndproc_arg(WNDPROC p, void *arg)` を使ってコンテキストを変更できます。アロケータ例では、異なる状態オブジェクト用に複数のトランスペイルを生成したり、動的に切り替えたりする方法を示しています。この手法は、トランスペイルがアンウインドテーブルを持たないため Windows Control Flow Guard 下でも安全に機能し、グローバル変数を使わずにウィンドウごとのデータを付与する低レベルの手段を示しています。