他の潜在的な貢献者への注意: 主張を述べる際に、抽象的または数学的な表記法を遠慮なく使用してください。回答が不明瞭な場合は説明を求めますが、それ以外の場合は、気楽な方法で自由に表現してください。
はっきり言って私はない「安全な」 を探しているわけhead
ではなく、特に を選択することにhead
特別な意味があるわけでもありません。質問の核心は、文脈を提供する とhead
の議論の後に続きます。head'
私はここ数か月間 Haskell をハッキングしてきました (これが私のメイン言語になったくらいです) が、一部の高度な概念や言語の哲学の詳細についてはよく知りません (学ぶ意欲は大いにありますが)。私の質問は技術的なものではなく (技術的なものであっても私がそれに気づいていないだけの場合を除く)、哲学に関するものです。
この例では、 についてお話しますhead
。
ご存知かと思いますが、
Prelude> head []
*** Exception: Prelude.head: empty list
これは から導かれますhead :: [a] -> a
。まあ、当然です。明らかに、(何気なく)型のない要素を返すことはできません。しかし同時に、定義するのは簡単です(自明ではないにしても)。
head' :: [a] -> Maybe a
head' [] = Nothing
head' (x:xs) = Just x
これについては少し議論がありましたここ特定の発言のコメント欄で、アレックス・スタングルはこう述べている。
「すべてを「安全」にせず、前提条件に違反した場合に例外をスローすることには十分な理由があります。」
私は必ずしもこの主張に疑問を抱いているわけではありませんが、これらの「正当な理由」が何であるかについては興味があります。
さらに、ポール・ジョンソンはこう言う。
たとえば、「safeHead :: [a] -> Maybe a」と定義できますが、空のリストを処理するか、それが起こり得ないことを証明するのではなく、「Nothing」を処理するか、それが起こり得ないことを証明する必要があります。
そのコメントから読み取った調子から、これは難易度/複雑さ/何かの顕著な増加であると示唆されていますが、彼が何を言おうとしているのかはよくわかりません。
スティーブン・プルジナ氏は(なんと2011年に)こう言っています。
「たとえば「head」がクラッシュ耐性を持たないのには、もっと深い理由があります。多態的でありながら空のリストを処理するには、「head」は常に、特定の空のリストには存在しない型の変数を返す必要があります。Haskell でそれができれば Delphic になるでしょう...」。
空のリスト処理を許可するとポリモーフィズムは失われますか? そうであれば、どのように、そしてなぜですか? これが明らかになる特定のケースはありますか?このセクションについては、@Russell O'Connor が十分に回答しています。さらなるご意見ももちろん歓迎いたします。
明確さと提案に応じてこれを編集します。提供していただける考えや論文などがあれば、ぜひお知らせください。
ベストアンサー1
空のリスト処理を許可するとポリモーフィズムは失われますか? そうであれば、どのように、そしてなぜですか? これが明らかになる特定のケースはありますか?
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. あなたの質問の背景について、他にもコメントがあります。リストが空でないという前提条件がある場合、リストを使用する代わりに関数シグネチャで空でないリスト型を使用してそれを強制する必要があります。