Haskellの `head` はなぜ空のリストでクラッシュするのか(あるいはなぜ *空のリストを返さないのか)?(言語哲学)
質問
他の投稿者候補への注意 抽象的な表現、数学的な表現も遠慮なく使ってください。回答が不明確な場合は説明を求めますが、それ以外は自由に表現してください。
はっきり言っておくと、私は
ではない
を探しているのです。
head
を選択したわけでもなく、また
head
を選択することも、特に例外的に意味があります。質問の要点は
head
と
head'
であり、文脈を提供する役割を担っている。
私は数ヶ月間Haskellをハッキングしてきました(私のメイン言語となったほど)。しかし、私はいくつかのより高度な概念や言語の哲学の詳細についてよく知らないことは認めます(学ぶ意欲は十分ありますが)。私の質問は、技術的なものというよりも(技術的であり、私がそれに気づいていないだけであれば)、哲学の1つです。
この例では、私が話しているのは
head
.
想像するに、ご存知の通りです。
Prelude> head []
*** Exception: Prelude.head: empty list
これは
head :: [a] -> a
. 十分公平です。明らかに、(手を振って)型がない要素を返すことはできません。しかし同時に、(些細なことではありますが)単純に
head' :: [a] -> Maybe a
head' [] = Nothing
head' (x:xs) = Just x
という議論を少し見たことがあります。 ここで のコメント欄で少し議論しているのを見かけました。注目すべきは、ある Alex Stangl の発言です。
「すべてを"safe"にせず、前提条件に違反したときに例外を投げるには、それなりの理由があります」。
私は必ずしもこの主張に疑問を持っているわけではありませんが、これらの"good reasons"が何であるのかに興味があります。
さらに、ポール・ジョンソンはこう言っています。
「例えば "safeHead :: [a] -> Maybe a" を定義することができますが、今度は空のリストを処理するか、それが起こりえないことを証明するかではなく、 "Nothing" を処理するか、それが起こりえないことを証明しなければならないのです」。
そのコメントから読み取れるトーンは、これが難易度/複雑さ/何かの顕著な増加であることを示唆していますが、彼がそこに出しているものを私が理解しているかどうかはわかりません。
あるSteven Pruzinaはこう言っています(2011年、以下同)。
"例えば'head'がクラッシュしないようにできないのには、もっと深い理由があります。多相でありながら空のリストを処理するために、'head' は常に特定の空のリストから欠落した型の変数を返さなければなりません。Haskellがそれを実現できれば、Delphicなのですが..."。
空リストの処理を許可することで、ポリモーフィズムは失われるのでしょうか?もしそうなら、どのように、そしてなぜですか?このことを明らかにするような特別なケースがあるのでしょうか? このセクションは @Russell O'Connor によって十分に回答されています。 もちろん、さらなる考えは歓迎されます。
私は、明確さと提案の指示に応じてこれを編集します。どんな考えでも、論文などでも、提供していただけるとありがたいです。
どのように解決するのですか?
<ブロッククオート空のリストを扱えるようにすると、ポリモーフィズムは失われますか? のリストを処理することによって失われますか?もしそうなら、どのように、そしてなぜですか? このことが明らかになるような特定のケースはありますか? 明らかになりますか?
の自由定理は
head
は次のように記述します。
f . head = head . $map f
この定理を応用して
[]
は次のことを意味する。
f (head []) = head (map f []) = head []
この定理は、すべての
f
に対して成り立つので、特に
const True
と
const False
. これは
True = const True (head []) = head [] = const False (head []) = False
このように、もし
head
が適切に多相であり
head []
が合計値であった場合
True
と同じになる。
False
.
PS. あなたの質問の背景について、もしリストが空でないという前提条件があるなら、リストを使う代わりに関数シグネチャで空でないリスト型を使ってそれを強制すべきだという趣旨の他のコメントもあります。
関連
-
[解決済み] Haskellです。パターンでのパースエラー
-
[解決済み] Hindley-Milnerのどの部分が理解できないのでしょうか?
-
[解決済み】Weak Head Normal Formとは何ですか?
-
[解決済み] Haskellの "Just "構文とは?
-
[解決済み] HaskellとF#の主な違いは何ですか?[クローズド]
-
[解決済み] GHCiから言語拡張を有効にするには?
-
[解決済み] リストからn番目の要素を得るには?
-
[解決済み] HaskellのPrelude.readはなぜMaybeを返さないのですか?
-
[解決済み] Lazy I/Oの何がそんなに悪いのか?
-
[解決済み] GHCiで関数の型宣言を明示的に行うには?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] 機能における非網羅的なパターン【重複あり
-
[解決済み] フリーモナドとは何ですか?
-
[解決済み] Haskell における `mod` と `rem` の違い
-
[解決済み] Haskellのマルチコアプログラミングはどうなっているのか?
-
[解決済み] Haskellの "Just "構文とは?
-
[解決済み] レコードの単一フィールドを割り当て、残りのフィールドはコピーするための省略記法?
-
[解決済み] Haskellのガードとif-then-elseとcaseの比較
-
[解決済み] Haskellの派生はどのように行われるのですか?
-
[解決済み] インデックス付きモナドとは?
-
[解決済み] このHaskellのコードはなぜ-Oをつけると遅くなるのですか?