Open7

Gleam やる

おーみーおーみー

インストール

lsp serverは gleam lsp で起動するタイプだった。

flake.nix
{
  description = "A very basic flake";

  outputs = { self, nixpkgs }:
    let pkgs = nixpkgs.legacyPackages.x86_64-linux; in
    {
      devShells.x86_64-linux.default = pkgs.mkShell {
        buildInputs = [ pkgs.gleam pkgs.erlang pkgs.rebar3 ];
      };
    };
}

rebar3 はErlangのビルドシステム。

おーみーおーみー
app/web.gleam
import wisp

pub fn middleware(
  req: wisp.Request,
  handle_request: fn(wisp.Request) -> wisp.Response,
) -> wisp.Response {
  use <- wisp.log_request(req)
  use <- wisp.rescue_crashes

  handle_request(req)
}

use <- f() ってのがかなりおもろそう

おーみーおーみー
app/router.gleam
import wisp.{type Request, type Response}
import gleam/string_builder
import app/web

pub fn handle_request(req: Request) -> Response {
  use _req <- web.middleware(req)

  let body = string_builder.from_string("<h1>Hello, Wisp!</h1>")

  wisp.html_response(body, 200)
}

ここでよくみてみよう、2引数をとるはずの web.middleware の呼び出しが1引数で行われているようにみえるが……要するにKokaの with みたいな感じで呼び出し側の以降の処理が最終引数の関数としてぶん投げられている気配を感じる。

おーみーおーみー

Gleam lacks exceptions, macros, type classes, early returns, and a variety of other features, instead going all-in with just first-class-functions and pattern matching.

そうなんだ

This makes Gleam code easier to understand, but it can sometimes result in excessive indentation.

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

あーこいつらは非同期的に実行されるんかな、昔のJSのコールバック hellですわね

おーみーおーみー

が、use を使うとこうなる。Kokaの with〜〜〜〜

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