1. ホーム
  2. haskell

初心者はHaskellかStandard MLか?[終了しました]

2023-08-09 23:40:39

質問

私は離散構造の低学年の講義を担当することになりました。教科書は 離散構造・論理・計算可能性 は、関数型プログラミング言語での実装に適した例と概念を含んでいるからです。(また、良い教科書だとも思っています)。

DSの概念を説明するために、学生が使えるようなわかりやすいFP言語が欲しいです。ほとんどの学生は、せいぜい1学期か2学期、Javaでプログラミングをしたことがあるくらいでしょう。Scheme、Erlang、Haskell、Ocaml、SMLを検討した結果、HaskellかStandard MLに落ち着きました。以下の理由からHaskellに傾いていますが、どちらかの現役プログラマーの方のご意見を伺いたいと思います。

  • HaskellとSMLの両方がパターンマッチを持っており、再帰的なアルゴリズムを簡単に記述できる。
  • Haskellにはリスト内包があり、数学的に表現されるリストとうまくマッチしている。
  • Haskellは遅延評価を持っています。リスト内包のテクニックを使って無限リストを構築するのに最適な方法。
  • SMLは、関数の定義と使用の両方が可能な、真にインタラクティブなインタプリタを持っています。Haskellでは,関数は別のファイルで定義され,対話型シェルで使用する前にコンパイルされなければなりません.
  • SMLでは,関数の引数や戻り値の型を,理解しやすい構文で明示的に確認することができます.例えば,val foo = fn : int * int -> int. Haskellの暗黙のカレー構文は、もう少し難解ですが、全く異質というわけではありません。たとえば、foo :: Int -> Int -> Int.
  • Haskell はデフォルトで任意精度の整数を使用します。これはSML/NJの外部ライブラリです。また、SML/NJはデフォルトで出力を70文字に切り詰めます。
  • Haskellのラムダ構文は微妙で、シングルバックスラッシュを使います。SMLはより明示的です。このクラスでラムダが必要になるかどうかは分かりませんが。

基本的には、SMLとHaskellはほぼ同等です。Haskellのリスト内包や無限リストが好きなので、Haskellに傾いています。しかし、Haskellのコンパクトな構文における膨大な数のシンボルが、学生の問題を引き起こさないか心配です。SOの他の投稿を読むと、HaskellはFPを始める初心者にはお勧めできないようです。しかし、私たちは本格的なアプリケーションを作るつもりはなく、簡単なアルゴリズムを試してみるだけです。

どうでしょうか?


編集:皆さんの素晴らしい回答を読んで、私の箇条書きのいくつかを明確にすべきです。

SMLでは,インタプリタでの関数定義と外部ファイルでの関数定義の間に構文上の区別はありません.例えば、階乗関数を書きたいとします。Haskellではこの定義をファイルに入れて、GHCiに読み込ませることができます。

fac 0 = 1
fac n = n * fac (n-1)

私にとっては、これは明確で簡潔であり、本の中の数学的定義と一致しています。しかし、GHCiで直接関数を書きたい場合は、別の構文を使用する必要があります。

let fac 0 = 1; fac n = n * fac (n-1)

対話型インタプリタを使って作業するとき、生徒がファイルとコマンドラインの両方で同じコードを使えると、教える立場からするととてもとても便利です。

関数の明示的な確認」というのは、SMLでは関数を定義すると、すぐに関数名、引数の型、戻り値の型がわかるという意味です。Haskellでは :type というコマンドを実行すると、やや分かりにくいカレー記法になります。

Haskellのもう1つのクールな点 -- これは有効な関数定義です。

fac 0 = 1
fac (n+1) = (n+1) * fac n

ここでも、教科書に載っているような定義と一致しています。SMLではできないことです。

どのように解決するのか?

私がHaskellを愛するのと同じくらい、離散数学とデータ構造のクラス(そして他のほとんどの初心者のクラス)にはSMLを好む理由は以下の通りです。

  • Haskellプログラムの時間と空間のコストは、専門家であっても予測するのが非常に困難です。 SMLはマシンを吹っ飛ばす方法をより限定的に提供します。

  • 対話型インタープリタでの関数定義の構文は以下の通りです。 同一 であり、カットアンドペーストが可能です。

  • SMLにおける演算子オーバーロードはまったくもってインチキですが、単純でもあります。 Haskellのクラス全体を型クラスなしで教えるのは難しそうです。

  • を使って生徒がデバッグできる print . (ただし、コメントで指摘されているように、Haskellでもほぼ同じ効果を得るために Debug.Trace.trace .)

  • 無限のデータ構造は人々の心を揺さぶります。 初心者の場合は、refセルとサンクを備えたストリーム型を定義させる方がよいでしょう、そうすれば、それがどのように機能するかを知ることができます。

    datatype 'a thunk_contents = UNEVALUATED of unit -> 'a
                               | VALUE of 'a
    type 'a thunk = 'a thunk_contents ref
    val delay : (unit -> 'a) -> 'a thunk
    val force : 'a thunk -> 'a
    
    

    これでもう魔法ではなくなり、ここからストリーム(無限リスト)へ行くことができるようになりました。

  • レイアウトはPythonのように単純ではなく、混乱することがあります。

Haskellが有利なのは2か所です。

  • コアHaskellでは、関数の定義の直前に関数の型付けを書くことができます。 これは学生やその他の初心者にとって非常に便利です。 SMLでは型付けを扱う良い方法がないのです。

  • Haskellはより良い具体的な構文を持っています。 Haskellの構文はMLの構文より大きく改善されています. 私が書いた MLプログラムにおいて,どのような場合に括弧を使うかについての短いメモ を書きましたが,少しは参考になったでしょうか.

最後に、両断する剣があります。

  • Haskell のコードはデフォルトで純粋なので、学生が不純な構造体 (IO モナド、状態モナド) に偶然出くわすことはまずないでしょう。 しかし、同じ意味で、彼らは印刷することができませんし、もしI/Oを行いたいのであれば、最低限でも do という記法と return は紛らわしい。

関連する話題として、コース準備のためのアドバイスがあります:見落とさないでください。 純粋に関数的なデータ構造 クリス・オカサキ著)を見逃してはいけません。 たとえ学生にこれを使わせないとしても、あなたは間違いなく一冊持っていたいと思うはずです。