2 ポイント 投稿者 GN⁺ 2023-08-26 | 1件のコメント | WhatsAppで共有
  • 2009年ごろから2019年ごろまで Haskell を主言語として使っていたプログラマが、今では個人プロジェクトや求職において Haskell を第一の選択肢に置かなくなった
  • Haskell の魅力はモナドや DSL そのものよりも、代数的なコード推論と強い型システムがもたらす安全なリファクタリング、不変条件の表現にあった
  • 離れるようになった理由は、高度な型機能を好む文化、洗練されていないツール、GHC と標準ライブラリの継続的な非互換変更が積み重なったためである
  • それでも高階関数、do 記法、レンズ、宣言的ライブラリ、高度な型抽象化は、他の言語では簡単に置き換えられない長所として残っている
  • Haskell はより良いプログラマになるために学ぶ価値は大きいが、組織の標準言語にするならツール品質と言語安定性のコストを受け入れる必要がある

Haskellを標準言語として使っていた時期と現在の立ち位置

  • 約10年間、Haskell は新規プロジェクトの標準言語だった
    • 2009年ごろに Haskell に触れてから、2019年ごろに Ruby と C++ を主に使う職場へ移るまで、自分を Haskell プログラマだと認識していた
  • コマンドラインツール、Web サービス、グラフィックアプリケーション、小さなスクリプトなど、さまざまな用途で Haskell を使っていた
  • 今では Haskell を完全に拒絶しているわけではないが、個人プロジェクトでも標準言語ではなく、以前のように「Haskell の職場」をわざわざ探すこともない
  • この判断は Haskell が悪いという結論ではなく、個人的に Haskell から離れた理由に近い

Haskellに惹かれた理由

  • 代数的にコードを扱える性質

    • Haskell の最大の魅力は、コードを記号的・代数的に推論できる点だった
    • たとえば double n = n + n という関数があるとき、double xx + x に置き換える変換は Haskell では常に正しい
    • 多くの命令型言語では、double(i++)(i++) + (i++) が異なる動作をすることがある
      • 前者は i を1回増やす
      • 後者は i を2回増やす
    • この性質のおかげで、小さな機械的変換を積み重ねて大きなリファクタリングをより安全に進められる
    • Ruby のコードベースでの大規模なリファクタリングは非常に不安になり得るが、Haskell のコードベースでははるかに容易な場合がある
  • 厳格だが過度に騒がしくない型システム

    • Haskell の型システムは厳格でありながら、型推論のおかげで Java のように型注釈が過剰に多くならない
    • 型クラスは、型を意識しなければならない場面でも煩雑さを減らしてくれる
    • 良い Haskell コードは「壊れやすい(brittle)」性質を持つ
      • 誤った抽象化が静かに歪んで誤ったプログラムを許してしまうことがない
      • 問題があればコンパイルに失敗する
    • NonEmpty 型は、少なくとも1つの要素を持つリストを表す
      • map のような長さを保持する操作は NonEmpty を返す
      • append のような長さを増やす操作も NonEmpty を返す
      • filter のように結果が空になり得る操作は通常のリストを返す
    • ファイルパスのリストが NonEmpty でなければならない関数には、コマンドライン引数をそのまま渡せず、まず空でないことを確認しなければならない
    • 後から拡張子フィルタの段階を追加すると結果が空になり得るため再確認が必要になるが、空リストを誤って渡す経路はコンパイラが防いでくれる
  • 型で不変条件を保つやり方

    • Haskell を長く使うと、プログラムの不変条件を型で表し、コンパイラに検証させるやり方に慣れていく
    • これは複雑な型レベル計算だけを意味するものではない
    • SQL エスケープの有無を RawStringSanitizedString のようなラッパー型で区別できる
      • Web API が RawString を返しても、データベース層は SanitizedString だけを受け取るようにできる
    • Maybe フィールドが多い表面的な表現を、必要な情報の存在が保証された内部表現に変換できる
    • 独立してテストできる程度にだけジェネリックにするというやり方も可能である
  • DSLと高階関数が自然な言語

    • Haskell はマクロなしでも簡潔なドメイン固有言語を作りやすい
    • config-ini は INI 設定ファイルを扱うライブラリの例である
      • 命令型のパースインターフェースではなく宣言的インターフェースを使う
      • 設定型の特定部分を INI ファイル構造の特定部分に対応付ける
      • 同じインターフェースで読み込み、書き込み、差分最小更新を行う
    • Ruby の DSL は動的メタプログラミングやグローバルな monkeypatching に依存し得るが、Haskell の DSL は柔軟な構文やモナドのオーバーロードのような機能によって、特定のファイルやコード領域に閉じ込めやすい
    • Haskell は高階関数の扱いも自然にする
      • (+) は2つの数値引数を取って足す関数としてそのまま使える
      • pairwiseProduct = zipWith (*) のように、2つのリストの要素ごとの積を非常に短く表現できる
    • Haskell は、Perl が文字列を扱わせてくれるように関数を扱わせてくれる言語だ、というたとえがふさわしい

Haskellから離れた3つの要因

  • 難解なスタイルを好む空気

    • 1つ目の要因は、スタイル上の新奇性への嗜好である
    • Haskell コミュニティは新しい抽象化を継続的に実験し構築している
      • 抽象代数学や圏論から持ち込まれたアプローチ
      • より多くの計算を型レベルへ持ち上げて誤った状態を制限するアプローチ
    • Servant の型レベル Web APIcomonad でメニューシステムを表現した事例 は、問題領域を新しい方法で表現しようとする実験である
    • しかし日常的なコードでは、こうした実験的アプローチが、最初に見える利点以上の問題を生むことがある
    • あるコンパイラプロジェクトの例では、AST ノードが式の型を型パラメータとして持っていた
      • 型エラーのある構文木を作ると、コンパイラ自体がコンパイルできなくなる
      • 当初はいくつかのバグを捕まえられた
      • 多くの最適化パスが型規律に合わないとき、キャストや GHC をなだめるための工夫でコードが複雑になった
      • 最終的には AST から型パラメータを取り除いた
    • 「fancy types」アプローチを試したプロジェクトのうち約4分の3では、十分な価値はなかったと評価している
    • Simple Haskell の流れは、実験的機能を避け最小限の拡張にとどめるときに、この言語の長所を最も多く得られるという考えに基づいている
    • より複雑な型機能はコミュニティやライブラリに広く浸透している
    • 複雑な型抽象化は変更や保守を難しくし得るし、単純化した抽象化を最新の型レベル抽象化に戻そうとする試みが、コードサイズの増加、性能低下、可読性低下につながった経験もある
    • ただし Trees that Grow のように、コンパイラ段階ごとにインデックス付けされたデータ構造は、有用だった「fancy type-level feature」の例として残っている
  • 日常作業で輝けなかったツール

    • 2つ目の要因は、ぎこちないツール体系である
    • Haskell には、標準に近いビルドシステムや開発ツールが複数ある
    • これらのツールは概ね必要な仕事はしてくれるが、「愛したくなる」水準ではなかった
    • ormolu のように最小限の手間で役目を果たすツールもあったが、一部のツールでは継続的なバグや回避策が必要だった
    • Haskell のツールは10年間で改善したが、2019年時点では Rust Cargo の使い勝手や安定性に近いものはなかった
    • 新しくてより良いものを作り続けようとする Not-Invented-Here 的傾向も問題だった
      • パッケージのテキストフォーマットまで hpack で作り直そうとする流れがある
      • こうした試みが何年も95%完成の状態にとどまることに苛立ちを覚える
    • Haskell のツールがひどいと言いたいわけではないが、「そこそこ良い」では高まった基準を満たせない
  • 続き続ける非互換な変更

    • 3つ目の要因は、Haskell 言語と GHC が経験している継続的な変化である
    • GHC は事実上、唯一合理的な公開 Haskell 実装として扱われている
    • Haskell は、過去の誤りや不整合を、標準ライブラリや言語の基本部分においても段階的に修正しようとしている
    • こうした変化は、言語をよりクリーンで一貫した基盤へ導き得るが、利用者には継続的に小さな摩擦を生む
    • 2015年の Foldable-Traversable Prelude changes は、そのような変化を示す例である
    • 古い Haskell プロジェクトは、外部依存がなくても最新の GHC でビルドできないことがある
      • superclass の追加
      • import の削除
      • あいまいになった多相性のための型シグネチャ追加
    • 修正はたいてい小さいが積み重なり続け、以前と少しずつ違う部分が利用者の注意を要求する
    • Rust の epochs 更新方式 は、安定機能に対する後方互換契約を明示し、意図的な breaking change を epoch の後ろに隠す方式として対照的である

それでも恋しく思うHaskellの長所

  • Haskell の代数的なコード記述とリファクタリングは、今でも強みである
    • Rust も Haskell と多くの長所を共有しているが、小さな機械的リファクタリングがプログラムの意味を保つという確信は、Haskell ほど容易には得られない
  • 型システムも、他の言語が通常は持たない機能を提供する
    • 2023年の主流言語は、2009年より静的型付け機能が大きく進歩している
    • それでも higher-kinded types 上の抽象化のような機能は Haskell の差別化要因である
  • Haskell のライブラリエコシステムは入り混じっている
    • 半ば保守されたオープンソースライブラリ
    • 個々の作者が自分流に世界を再構成しようとする小さな王国
    • 必要だが互いに異なる文字列類似型たち
  • それでも Haskell には、他の言語では半分くらいしか実現できない優れたライブラリや抽象化がある
    • レンズは、十分に使ってみないと良さが見えにくい強力な抽象化である
    • Brick は宣言的なブロックで非常に優れたターミナル UI ライブラリを提供する
    • diagramsmusic-suite も宣言的 API の好例である
  • do 記法も大きく恋しく思う機能である
    • 重要なのは do 自体より、束縛を追加してもインデントの深さが増え続けない記法である
    • Ruby のネストした flat_map は軸が増えるたびにインデントが深くなる
    • Haskell の do 記法は同じ組み合わせを平坦に表現できる
  • do 記法は、async/await スタイルの構造化並行性、同時トランザクション確率的プログラム を同じ軽量な構文で埋め込めるようにする

Haskellを学ぶべきか、使うべきか

  • 「この言語を学ぶべきか、使うべきか」という問いへの答えは、目標によって異なる
  • より良いプログラマになることが目標なら、Haskell は学ぶ価値が大きい
    • Haskell は興味深く強力な言語である
    • Haskell を学んだ経験はプログラミング能力を高めたと評価している
  • 実用が目標なら、より慎重であるべきだ
    • Haskell の長所は実際に存在する
    • 個人や組織が前述の摩擦をどれだけ受け入れられるかと比べる必要がある
    • Haskell から十分な利益を得て、小さな不便を小さな傷の水準にとどめられる個人や組織も存在する
  • 明確なイエス・ノーを求めるなら、答えは「Haskell を使わないほうがよい」に近い
    • エンジニアリング組織を作るなら、Haskell を標準言語として据えないという判断である
    • 良いツールの価値と悪いツールのコストをどちらも知っているからである
    • 安定した言語、明確なコードエコシステム、優れたツールをすぐ提供できる言語を好む
  • それでも Haskell は、プログラムの安全性と正確性のための優れた道具を提供する
    • 特定の文脈では、悪いツールや不要な type family を防ぐ linting を受け入れる価値があるかもしれない
  • Haskell はもはや個人的に合う言語ではないが、Haskell がこの世界に存在しなかったなら、世界はもっと悪かっただろうという結論に至る

1件のコメント

 
GN⁺ 2023-08-26
Hacker News の意見
  • Haskell を10年ほど使って、最近は生計を立てる手段としては離れたが、著者の最初の指摘には確かに同意する: Haskell コミュニティは学びを非常に重視する
    好奇心旺盛な人たちと働き、常に教えることも学ぶこともあるのはよいが、試したアイデアを捨てるのは苦手な方なので、プロフェッショナルな Haskell コードベースは厳格に管理しないと、「できるけれど使わない方がよいもの」がたまりやすい
    ただし ツールチェーンについては意見が違う。Haskell のツールがいまいちなのは事実だが、Python、JS、Java、Rust、Elm を使ってみると、たいていのツールもいまいちで、むしろ Haskell のツールチェーンが恋しくなった。cargo は素晴らしいが例外に近く、Rust が古くなった後もこの状態を避けられるのかは気になる

    • いくつもの言語を使ってきたが、Haskell のツールは最悪に近かった。language serverはランダムなエラーで頻繁に壊れ、Haskell のバージョン管理を ghcup に任せるべきか stack に任せるべきかも毎回迷う
      たまに作業するプロジェクトがあるが、次に開いたらまた動かないだろうと100%確信している。Python の依存関係・仮想環境管理も同じくらいひどいが、Poetry はかなりよく、Ruby は chruby/rbenv/rvm のどれを使っても同じようにうまく動き、Bundler もきちんと回る。Java は欠点があっても IDE 体験は最高水準で、リファクタリングは Haskell ほど安全ではなくても非常に簡単にできる
    • Cargoは Ruby の Bundler のような古いアイデアから進化したものなので、この種のツールの中では系譜がかなり長い方だ
      Bundler はおおむね悪くなく、同意できない設計上の選択はあっても、正しい道をたどれば多くの部分がうまく噛み合う。言語ツールも十分に壊れにくい形で作ることができるし、cargo を直接それほど多く使ったわけではないが、本当に同クラス最高なら、その状態を維持しても驚かない
    • Java ツールが「いまいち」の範疇に入るというのは少し信じがたい。Java 自体についてはいろいろ否定的なことを言えるが、無料・商用ツールは群を抜いた水準だ
    • Haskell のツールのせいで、また本格的に掘り下げる気が失せた。一方で Purescriptは、何度か触るたびにかなり滑らかな体験を与えてくれた。特に JS ツールに慣れているならなおさらだ
    • ツールの議論に .NET 言語や Swift が出てこない理由が気になる。Visual Studio や Xcode のような IDE が第一級のツールだからかもしれないし、オープンソース界隈がビッグテックへの依存を避けがちなためかもしれない
  • ツール面で Haskell には、知る限り他の言語が競争しにくいものが1つある: Hoogle
    Hoogle は驚くほど優れている。Haskell でやりたいことを伝えると、Haskell でできることを教えてくれる。Rust でも似た試みがあり、Nim 用の Noogle も作ろうとしたが、「関数に引数を渡すこと」と「関数を呼び出すこと」が明確に分かれる言語では、同じようには機能しない
    ResultBox が絡む Rust コードを見るたびに、Hoogle と同じくらい有用な Roogle があればと思う。それ以外の Haskell ツールには長所がない。かなりの部分は、既存のものを改善するより「革新的な」何かを作ろうとするコミュニティの本能のせいに見える

    • Hoogleが途方もなく有用だという点には強く同意する。ただ、他のツールについては haskell-language-server を毎日使っていて、生産性ははるかに良くなった
      完璧ではないが、5年前と比べればずっとましだ
    • Hoogle は本当にすごい。そこから着想を得て、C++ 向け関数型プログラミングライブラリ FunctionalPlusにも似たものを実装した: https://www.editgym.com/fplus-api-search/
      もっと多くのプロジェクトがこういう方向を取ってくれるとよい
  • 最大の問題は、GHCが標準ライブラリである特定の base バージョンに結び付いている点だと思う
    base が変わり、新しい GHC バージョンがそのバージョンだけをサポートすると、より新しい GHC を使うために事実上すべての依存関係を変えなければならない。GHC 9.6 でコンパイルしたコードがなぜ base 4.18.0.0 を使わなければならないのか、まだ理解できていない。GHC バイナリがコンパイル対象コードの Data.List モジュールのバージョンをなぜ気にする必要があるのか
    base が公開する GHC 専用要素が特定の GHC バージョンに紐づくのは理解できるが、残りまでそうであるべきかは分からない。ただ、これを直すために base を複数のパッケージに分割する作業が進行中だと理解している: https://gitlab.haskell.org/ghc/ghc-wiki-mirror/-/blob/master...

    • 引用した部分にヒントがある。より新しい GHCが古い base コードを無効だとして拒否する可能性がある
    • 内部の データ型が異なる可能性があるからだ。異なる base 実装にリンクされたライブラリ同士が Data.List のインスタンスを受け渡しするなら、問題が起きる
      たとえば Data.List のリストがあるとき、異なる2つのライブラリ関数の結果をそのリストに連結できるだろうか
    • 指摘のとおり、再インストール可能な base は誰もが望む目標だ。現状は歴史的理由と、コンパイラ内部に結び付いた基本要素が非基本要素と結合していることによるところが大きく、十分な労力をかければ改善できる
  • Haskellへの関心が徐々に冷めた大きな理由が3つあるとすれば、難解なコードを称賛して保守を難しくするスタイル上の新しもの好み、日常作業をより鈍重にするぎこちないツール、たまにではあるが継続的に気を配る必要があり、定期的に破壊的変更をもたらす絶え間ない変化だった
    妥当な指摘。2010〜2012年にHaskellをかなり学んだが、言語自体は素晴らしい一方で、ドキュメントとツールは扱いにくかった。コミュニティはCabalと悪名高いCabal hellからStackへ移り、その後またCabalへ戻り、全体としては良くなった
    一方で、他のプログラミング言語も関数型プログラミングの要素を取り込んだ。たとえばJavaはStreams、関数、ラムダ、代数的データ型、records、パターンマッチングを追加し、構文はHaskellほど優雅でなくても、関数型プログラミングの基本概念は入っている

    • 監獄から抜け出そうとする絶望的な試みの中で、囚人たちは狭い格子越しに見える光に着想を得た奇怪な儀式を受け入れ、自分たちの言語を汚した
      そうして自ら終わりなき苦痛の穴を作り出したが、窓の外の木に光が作る色を見られるほど光線が低くはないため、かろうじて耐えられるものになった。外から来た者たちは、自ら作った闇に適応した方言と、光の中では繁栄できるがそこでは窒息する方言との間で引き裂かれ、急速に正気を失う
    • 列挙されている機能の大半よりも、効率的な不変データ構造のほうが関数型プログラミングには重要。Javaはそこで何を提供しているのか
    • CabalからStackへ行って、またCabalへ戻ったとは知らなかった。Haskellから数年離れていて、最後に使ったときはStackが最もなめらかで、Cabalの多くの苦痛を解決したように見えた
      コミュニティがまたCabalへ戻ったのなら、何を見落としているのか気になる
  • こうした理由から**F#**へ移り、あまり振り返らなくなった。ときどき高階カインド型が恋しくなることはあるが、F#にもジェネリクスはあり、正直に言うとHaskellよりも単純なコードを書くよう強制される面があって、たいていその結果のほうが良い
    ただしF#はHaskellのような「達人っぽさ」は与えてくれない。Haskellのようでありながら、徹底して実務的だ。F#で多くのことを片付け、楽しく使っているが、たまにHaskellとはなぜうまくいかなかったのかと、ほのかに振り返ってしまう

    • こういう話を見られてうれしい。関数型プログラミングに入門したばかりで**F#**を楽しんでいるが、簡潔で実務寄りなのが良い
      Haskellを使わないと何かを逃しているのではないかとよく気になっていたが、自分の目的にはおそらくそうではなさそうだ
  • Haskellを学ぶのは異星人の言語を解読しようとするようなものだ。普通のif-elseループや単純な変数代入に慣れているなら、頭がこんがらがる覚悟をしたほうがいい
    monadは宇宙怪物ではなく奇妙な抽象概念だが、頭をかきながら人生の選択を疑わせることがある。ライブラリも、必要なものを探すには半分空っぽの中古品店をあさるような感じで、ドキュメントも半分は象形文字のように読める
    性能も現実には遅延評価のせいで予想以上にメモリを食い、なぜ遅くなるのか長々と悩むことがある。仕事もHaskellに全振りした非常にニッチな会社でない限り見つけにくく、デバッグは関数型の象形文字の山から針を探すように感じられる

  • Scalaを使ってきたが、2つの世界の長所を与えてくれると思う。代数的に推論でき、リファクタリング後にコンパイルできればたいてい動く
    型推論とmonadもうまく機能し、Javaエコシステムの利点も得られる。難解になりすぎる場合は、ルールを破ってJavaに近い書き方もできる。他の人がどう考えているのか気になる

    • 同じ理由でScalaを本当に楽しく使ってきた。必要なら逃げ道があり、エコシステムも大きい
      ただしsbtは気が狂いそうで、開発体験の中でおそらく一番気に入らない部分だ
    • 同意。命令型/OOPコードから純粋関数型スタイルへ、なめらかに段階的移行できるようにしてくれる点も良い
  • Haskellの統括主体とメンテナーたちは、実際にこの言語が研究、実験、学術的探究に向いたものであることを意図しているように見える
    それ自体は問題ないが、どこかの時点で、Haskellを実用的で安定した道具として使おうとするプログラマーの利害と衝突せざるを得ない。必要なのは、実験的で最先端のものを別トラックとして示せる能力だと思う。pragmaであれパッケージレベルの宣言であれ、パッケージを見ただけで取り込むべきか分かるようにする必要がある
    そうすれば実務志向の開発者が「私たちはstable Haskellだけを使う」といった方針を採用できる。Haskellの採用が高まりすぎると、言語が慣性に閉じ込められ、最先端の概念を押し進められなくなるという「Avoid success at all costs」の力学は認めつつも、日常的な開発者がより制限され安定したHaskellの部分集合にとどまれる公式トラックが必要だ

    • その通り。この原則はA History of Haskell: Being Lazy with Class(2007)に中核原則として明記されている。PDFへの直接リンク: https://www.microsoft.com/en-us/research/wp-content/uploads/...
    • その役割を担うのがStackageだ。Stackageは一緒にビルドされ、テストに通ることが分かっている一貫したHaskellパッケージ集合を提供し、Stackage NightlyスナップショットとLTS(Long Term Support)リリースになる
      Javaは絶対にこういうものを得られないだろう。https://www.stackage.org/
    • そうした方向を促すSimple Haskellイニシアチブがある。ただし「このプロジェクトはsimple Haskellを使う」と言うためのフラグやpragmaはない
      単純さは結局、見る人次第だ。華やかな型機能も、その動作を内面化していれば型をより表現力豊かにし、コードをより安全に、さらにはより単純にする使い道がある
  • かなり良い記事。ただ弱い点は、望んでいないのに特定の新しく派手な型機能を使えと押し付けられるような圧力を感じたことがない、というところ。
    Servant の型レベル HTTP API が嫌なら、一段下がって warp を使えばいい。ライブラリは、過度に複雑な型が落とし穴になり得ることを理解しているので、しばしばこのように階層化されている。どこまで行くべきかについての直感は必要で、その過程には失敗も含まれる。

    • Haskell をよく知らないけれど Servant のアイデアがものすごく良さそうに見える人向けの、「どうか教えてください」系の良い記事を知っているか気になる。
      Servant のドキュメントは読んでみたが、当然ながら、自分が持っている以上の Haskell の理解を前提としていた。
  • この記事は本当に刺さった。1年半ほど、かなり産業寄りのアプリケーションで Haskell を使っていて、その前にも https://github.com/mattgreen/hython のような経験がそれなりにあった。
    20年のキャリアの中で久しぶりにかなり多くのことを学ばなければならず、それはドメインと言語が組み合わさった結果だ。刺激的でもあり消耗もするし、忙しい家庭生活と一緒に抱えるにはかなり大きな塊かもしれない。
    それでも言語は優れている。マネージャーはおおむね top-down 方式で書くことを勧めていて、それは Haskell の柔軟性が開発意図をよく伝えられるため、どう読まれるべきかを深く考えてそこから始めろ、という意味だ。多くの言語で function を何度も打ち込んで脳が省電力モードに入るのとは大きな発想の転換で、本当に書きやすいよう設計されている感じがする。
    しかし、制御されたエフェクトを monad で扱っても、構文はいまだに流し読みしにくい。1行があまりに密になり得るせいなのかもしれない。早期リターンがものすごく恋しいし、Rust の優れた LSP も恋しい。Haskell は 9.x の内部変更のせいで、パターンマッチを埋めてくれる機能も最近失ったし、monad を積むのはいまだに嫌で、よく間違える。コンパイル時間は、特に lens ライブラリに出くわすと過酷になり得る。
    デフォルトの遅延評価も好きではない。コミュニティも、Haskell プログラムはこのデフォルトのせいで空間リークにずっと弱く、多くのプログラムでかなり長い間検出されないことがあり得る、とある程度認めている。システムプログラマーとしては悲鳴を上げたくなる。
    それでもコミュニティは、私が見た中で最も強いプログラマー集団の一つだ。ミームのように「頭がいい」という話を並べたいわけではなく、本当に深く考え、前へ押し進めるところが大きい。私たちのドメインであるプログラム解析には Haskell が手袋のようにぴったり合うが、それ以外の領域ではいまだに少し慎重だ。本質的には OCaml だが構文がより良いプログラミング言語への渇きがまだある。

    • 可読性のために早期リターンがどうしても必要なときがある。そういう場合は ExceptT を使うことを勧める: https://www.stackage.org/haddock/lts-21.8/mtl-2.2.2/Control-...
      インターフェースに ExceptT を露出させる必要もなく、内部で早期リターン用にだけ使って、関数は Either を返すようにすればいい。
    • 「OCaml だが構文がより良いプログラミング言語」を望んでいるのはあなただけではない。私もそうで、だから Reason が最初に出たときは深く掘り下げた。
      結局、大きな traction を得られなかったのは残念だ。
    • それは Scala 3 だ。Python に似た構文で、JVM のおかげで Haskell や OCaml よりはるかに大きなライブラリエコシステムがある。
      OCaml よりオブジェクト指向と関数型プログラミングの統合が優れていて、慣用的な OCaml コードは単純な変換で移しやすいほど似ている。