1733193890
2024-12-03 02:14:00
私は実稼働環境で Haskell を 8 年間使用してきました。私は本番環境で OCaml を 8 か月間使用してきました。
これら 2 つの言語を比較してみましょう。
Haskell はおそらく、私がこれまで見てきたすべての言語の中で最も洗練された構文を持っています (Haskell では依存的に型付けされたコードがすぐに醜くなる可能性があるため、おそらく Idris の方が優れています)。
できるだけ少ない文字数で自分のアイデアを表現できるのは、とても楽しいことです。
OCaml も ML ファミリーの言語であることは素晴らしいことですが、それでも、Haskell はより暗黙的です。
いくつかの例を比較してください。
文字列内のすべての数値の合計
標準ライブラリのみを使用する
ハスケル
-- strSum "100 -42 15" = 73
strSum :: String -> Int
strSum = sum . map read . words
OCaml
(* str_sum "100 -42 15" = 73 *)
let str_sum (str: string): int =
str
|> String.split_on_char ' '
|> List.filter_map int_of_string_opt
|> List.fold_left (+) 0
新しいバイナリ ツリー タイプの定義
ハスケル
data Tree a
= Leaf
| Node a (Tree a) (Tree a)
OCaml
type 'a tree =
| Leaf
| Node of 'a * 'a tree * 'a tree
解析中
以下のような行の解析が成功すると、「ステータス」が 0 に等しく、結果が偶数になる結果を返します。
"Status: -1 | Result: 42"
ハスケル
parseLine :: String -> Maybe Int
parseLine line = do
["Status:", "0", _, "Result:", result] Just $ words line
n readMaybe result
guard $ even n
pure n
OCaml
let parse_line (line: string): int option =
let ( let* ) = Option.bind in
let* result =
match String.split_on_char ' ' line with
| ["Status:"; "0"; _; "Result:"; result] -> Some result
| _ -> None
in
let* n = int_of_string_opt result in
if n mod 2 = 0 then Some n else None
上記は、ランダムなコードの一部です。これらは、それらの言語で作成できるすべてのプログラムについてのアイデアを与えるわけではありません。しかし、私は彼らが 2 つの言語の類似点と相違点をすぐに強調できることを願っています。
これにより、ゆっくりと次のポイントに進みます。
Haskell は、おそらく他のどのプログラミング言語よりもはるかに多くの機能を備えています (C++ も競合できます)。これは良いことでもあり、悪いことでもあります。
問題を最適な方法で解決するツールがあるので、それは良いことです。
そういうツールがあるからダメなんです。気が散ってしまうのです。 Haskell で問題を解決する必要があるたびに、私はそのソリューションを実際に実装する代わりに、そのソリューションを設計できるあらゆる方法をすぐに考えます。
私は何かを構築することに興味があり、暖かい夏の日に池の近くに座って、不正な状態を表現できないようにするには GADT よりも TypeFamilies + DataKinds の方が優れているかどうかを考えています。
既存の OCaml プロジェクトを使用する場合、以前の開発者がそれに対して行う可能性のある最悪のことは、変数名が貧弱で、ドキュメントが最小限で、200 以上の LOC 関数があることです。大丈夫です、特別なことは何もありません、私はそれを扱うことができます。
私が既存の Haskell プロジェクトに参加することになったら、以前の開発者が行う可能性のある最悪のことを行うことになります… まあ、これまでの 8 年間の Haskell 経験ではその準備はできません 😅
OCaml の方が生産性が高いと感じているのはこのためです。
Haskell の機能が時々恋しくなります。しかし、私は彼らの醜い側面と、彼らがあなたの出力に何ができるかを見てきました。
主要な機能を完全に比較した次の表を検討してください。
機能比較表
| 式指向の構文 | ✅ | ✅ |
| デフォルトでの不変性 | ✅ | ✅ |
| 高次関数 (HOF) | ✅ | ✅ |
| 匿名関数 (ラムダ) | ✅ | ✅ |
| 代数データ型 (ADT) | ✅ | ✅ |
| パターンマッチング | ✅ | ✅ |
| パラメトリック多態性 | ✅ | ✅ |
| 型推論 | ✅ | ✅ |
| モナド構文シュガー | ✅ | ✅ |
| ガベージコレクター | ✅ | ✅ |
| マルチスレッド化 | ✅ | ✅ |
| GADT | ✅ | ✅ |
| デフォルトでの純度 | ❌ | ✅ |
| 構成可能な怠惰 | ❌ | ✅ |
| 型クラス | ❌ | ✅ |
| より高次の種類 | ❌ | ✅ |
| オプトイン言語機能 | ❌ | ✅ |
| ファーストクラスのモジュール | ✅ | ❌ |
| 多態性バリアント | ✅ | ❌ |
| オブジェクト | ✅ | ❌ |
| クラスと継承 | ✅ | ❌ |
| 人間工学に基づいた可変性 | ✅ | ❌ |
正直に言うと、どちらのプログラミング言語もニッチな FP 言語です。したがって、公開されたばかりの最新の最新フレームワークに対する最高級のサポートを期待すべきではありません。
ただし、私の経験では、より多くのカスタム バインディングを記述する必要があるにもかかわらず、一般的なタスクの大部分については解決策があります。
たとえば、OCaml では次のものが見つかります。
等々。 Haskell についても同様の話があります。
Haskell エコシステムにはさらに多くのパッケージと、すぐに使えるソリューションがたくさんあると私はまだ言いたいです。
次の例で違いを示すのは簡単です。
の数 ストライプAPI クライアントライブラリ:
- ハスケル: 13
- OCaml: 1 (最後の変更は 8 年前なので、ほぼゼロです)
Haskell で解決策が見つかるかもしれません。しかし、多くの場合、あなたは発見するでしょう 多すぎる 解決策を考えても、どれを選択すればよいのかわかりません。
Haskell でライブラリを選択することは、習得する必要がある別のスキルになります。ハスケラーズ 推奨事項をブログに投稿することもできます 図書館の選び方について!そして、このジレンマに何度も直面することになります。
多くの場合、新しい Haskell ライブラリは、別の問題を解決するためではなく作成されます。
でも作者がそう言いたかったから 違う書き方をする (さまざまな抽象化を使用する、新しい機能を試すなど。LinearTypes に基づく新しいストリーミング ライブラリを望まない人はいないでしょうか?)。
GitHub API クライアントを作成して大量の JSON を解析するのは楽しいことではありません。
しかし、デザインするのは楽しいです コモナドを備えたロガー。
Haskell ツールは最も物議を醸す感情を呼び起こします。まるで感情のジェットコースターのようです。
- 🤩 フーグルは最高です!型シグネチャだけを使用してエコシステム全体を検索できます。
- 😨 待って、なぜビルド ツールのエラー メッセージがひどいのですか。動作中のプロジェクトのビルド プランが見つからなかったということはどういう意味ですか?
- 🤩 すべての依存関係に対するグローバルなコンテンツアドレス指定可能なストレージは、非常に素晴らしいアイデアです。
- 😨 パッケージを変更したので IDE を再コンパイルする必要があるとはどういう意味ですか?
- 🤩 パッケージドキュメント内のすべてのコードスニペットを自動的にテストできます!!!
- 😨 待って、なぜ私が使用しているこのバージョンの標準ライブラリにドキュメントがまったくないのですか?
等々。
Haskell ツールを使用することは、常に次の量子重ね合わせの中にいるようなものです。 「そのような健全な Haskell ツールがないのに、どうやって他の PL を使用するのですか??」 そして 「これらのユーザビリティの必需品なしで、ハスケラーはどうやってそのように生活できるのでしょうか??」。
一方、OCaml は異なる方法でヒットします。そのエコシステムは小さいため、実際に何かが機能していることを見つけるたびに驚かれます。
たとえば、言語サーバー プロトコル (LSP) に基づく OCaml 用の VSCode プラグインは、そのまま使用できます。何も問題はありませんでした。それ ちょうど動作します ™️
OCaml ツールを使い始めるときの人間工学は最高ではないかもしれませんが、簡単で堅牢です。そして、彼らはほとんどの時間働いています。
全体像を把握するには、両方の言語で利用可能なツールを完全に比較した次の表を参照してください。
ツーリング比較表
これは最も頻繁に使用するツールであるため、ツールのコンパイラの側面を個別に強調したいと思います。
特にコンパイラの提案。
FP 言語を使用する場合、コンパイラはあなたの親友です。自分の仮定が正確に体系化されていない理由を理解するために、この情報に大きく依存しています。
したがって、コンパイラは、最もアクセスしやすい方法で情報を提示する必要があります。
私の見解では、Haskell コンパイラーのメッセージは、文脈に沿った冗長で気が散る情報が多く含まれ、冗長になる傾向があります。
一方、OCaml コンパイラのメッセージは非常に簡潔です。場合によっては簡潔すぎることもあります。
次の例を考えてみましょう。
Haskell: コンパイラ メッセージの例
エラーのあるプログラム
コンパイラの出力
OCaml: コンパイラ メッセージの例
エラーのあるプログラム
コンパイラの出力

これはほんの 1 つの例にすぎません (おそらく最良の例ではありません) が、さまざまな言語で情報が表示される方法と型がどのように機能するかが異なることがすでにわかります。
標準ライブラリについても別途言及する価値があると思います。
これは、ある言語での最初のプログラムを形作り、今後のあらゆる旅をガイドします。
優れた標準ライブラリは、PL の成功の基礎です。
貧弱な標準ライブラリは、より優れた標準ライブラリ (競合する無数の代替標準ライブラリを含む) をめぐる終わりのない自転車置き場の基礎となります。
私は、標準ライブラリにはバッテリーが組み込まれるべきだという考えの大支持者です。
Option のような型、UTF-8 文字列、Map と HashMap、JSON と XML パーサー、非同期プリミティブなどを提供してください。そうすれば、依存関係の追跡とビルド ツールの貧弱な実装を学習する必要がなくなります。 (システムをアラカルトで構築 依存関係トラッカーとビルド ツールのスペースを徹底的に分析したものです)。
Haskell と OCaml はどちらも、必要最低限の標準ライブラリを備えています。それらには小さな違いがあります(たとえば、Haskell には Map と HashMap が含まれていません。OCaml には空でないリストと Bitraversable がありません)。しかし、全体的には精神的には似ています。
Haskell標準ライブラリは次のように呼ばれます。 base OCaml 標準ライブラリと呼ばれます。まあ、それは単なる「標準ライブラリ」です。
ただし、顕著な違いが 1 つあります。 Haskell ドキュメントの品質は、経験豊富な開発者さえ驚かせることがあります。
Haskell には、ドキュメントからソースにジャンプする機能など、さらにいくつかの優れた機能がありますが、そのような機能は OCaml 用にもクックされていると聞きました 👀
List データ型 (FP の基本構造の 1 つ) のいくつかのドキュメント スニペットを比較してください。
ハスケル


OCaml


このような機能の結果は明らかなので、各機能についてエッセイを書く必要はないと主張するかもしれません。
私は例主導のドキュメントのファンで、ドキュメントで使用例を見るのが大好きです。これにより、API を最適な方法で活用する方法がすぐにわかります。
このブログ投稿を次のように締めくくりたいと思います。
どちらの言語も、実際の産業ニーズをサポートするために長い道のりを歩んできました。
主流の言語に比べればまだ小さいです。
特定の SDK の存在に大きく依存していない場合は、任意の SDK を選択して、次のアプリのコーディングを楽しく行うことができます 🧡
しかし、私は最近 OCaml を好んでいます。この言語を使用すると実際に何かを構築することに集中できると感じているからです。
以下のコメント セクション以外にも、このブログ投稿に関するディスカッションがさまざまな場所で見つかります。
このブログ投稿が気に入った場合は、GitHub スポンサーで私の活動をサポートするか、インターネットで私をフォローすることを検討してください。
#Haskell #の本番環境での #年間の後にOCaml #で #か月