8

私は現在 Haskell を学んでいます。私がこの言語を選んだ動機の 1 つは、非常に高度な堅牢性を備えたソフトウェア、つまり、完全に定義され、数学的に決定論的で、クラッシュしたりエラーを生成したりしない関数を作成することでした。システムの述語 (「system out of memory」、「computer on fire」など) によって引き起こされる障害を意味するわけではありません。それらは興味深いものではなく、単にプロセス全体をクラッシュさせる可能性があります。また、無効な宣言 ( ) によって引き起こされるエラーのある動作も意味しませんpi = 4

代わりに、厳密な静的型付けを使用して (一部の関数で) それらの状態を表現不能およびコンパイル不能にすることによって削除したい、誤った状態によって引き起こされるエラーを参照します。私は心の中でこれらの関数を「純粋」と呼び、強力な型システムによってこれを達成できると考えました。ただし、Haskell はこのように「純粋」を定義しておらず、プログラムerrorがどのようなコンテキストでもクラッシュすることを許可していません。

例外をキャッチすることは非純粋ですが、例外をスローすることは純粋であるのはなぜですか?

これは完全に受け入れられ、まったく奇妙ではありません。残念なことに、Haskell は、 を使用した分岐につながる可能性のある関数定義を禁止する機能を提供していないようerrorです。

これが私がこれをがっかりさせる理由の不自然な例を次に示します。

module Main where
import Data.Maybe

data Fruit = Apple | Banana | Orange Int | Peach
    deriving(Show)

readFruit :: String -> Maybe Fruit
readFruit x =
    case x of
         "apple" -> Just Apple
         "banana" -> Just Banana
         "orange" -> Just (Orange 4)
         "peach" -> Just Peach
         _ -> Nothing

showFruit :: Fruit -> String
showFruit Apple = "An apple"
showFruit Banana = "A Banana"
showFruit (Orange x) = show x ++ " oranges"

printFruit :: Maybe Fruit -> String
printFruit x = showFruit $ fromJust x

main :: IO ()
main = do
    line <- getLine
    let fruit = readFruit line
    putStrLn $ printFruit fruit
    main

readFruit純粋な関数が実際に機能し、未処理の状態が原因でprintFruit実際​​に失敗しないことに私が偏執的であるとしましょう。このコードは、絶対に重要なルーチンで果物の値をシリアル化および非シリアル化する必要がある宇宙飛行士でいっぱいのロケットを打ち上げるためのものであると想像できます。

最初の危険は当然、パターン マッチングでミスを犯したことです。これにより、処理できない恐ろしいエラー状態が発生するからです。ありがたいことに、Haskell はそれらを防ぐための組み込みの方法を提供して -Wallおり、インクルード-fwarn-incomplete-patternsと AHAを使用してプログラムをコンパイルするだけです。

src/Main.hs:17:1: Warning:
    Pattern match(es) are non-exhaustive
    In an equation for ‘showFruit’: Patterns not matched: Peach

Peach フルーツをシリアル化するのを忘れていたためshowFruit、エラーがスローされていました。これは簡単な修正です。追加するだけです。

showFruit Peach = "A peach"

プログラムは警告なしでコンパイルされるようになり、危険が回避されました! ロケットを発射しますが、突然プログラムが次のようにクラッシュします。

Maybe.fromJust: Nothing

ロケットは運命にあり、次の障害のあるラインが原因で海に衝突します。

printFruit x = showFruit $ fromJust x

基本的fromJustに、それが発生するブランチを持っているので、絶対に「超」純粋でErrorなければならないので、それを使用しようとしてもプログラムをコンパイルしたくありませんでした。printFruitたとえば、行を次のように置き換えることで修正できます。

printFruit x = maybe "Unknown fruit!" (\y -> showFruit y) x

Haskell が厳密な型付けと不完全なパターン検出を実装することを決定したのは奇妙だと思います。これらはすべて、無効な状態が表現可能になるのを防ぐという壮大な追求の結果であり、プログラマーに分岐を検出する方法をプログラマーに与えないことで、フィニッシュ ラインのすぐ前に落ちerrorます。禁止されている。ある意味では、これにより Haskell は Java よりも堅牢性が低くなり、関数が発生できる例外を宣言する必要があります。

これを実装する最も簡単な方法はerror、何らかの形で関連付けられた宣言を介して、関数とその式で使用される関数をローカルで単純に未定義にすることです。ただし、これは可能ではないようです。

エラーと例外に関する wiki ページでは、コントラクトを介してこの目的のために「拡張静的チェック」と呼ばれる拡張機能について言及していますが、リンクが壊れているだけです。

基本的には、次のようになります。上記のプログラムをコンパイルしないようにするにはどうすればよいfromJustですか? すべてのアイデア、提案、解決策を歓迎します。

4

3 に答える 3

1

答えは、Haskell が残念ながら (まだ?) 提供していないレベルの完全性チェックが欲しかったというものでした。

あるいは、依存型 ( Idrisなど)、静的検証 ( Liquid Haskellなど)、または構文リント検出 ( hlint など) が必要です。

私は今 Idris について真剣に調べています。それは素晴らしい言語のようです。Idrisの創設者による、私が見ることをお勧めできるトークがあります.

これらの回答に対するクレジットは、@duplode、@chi、@user3237465、および @luqui に送られます。

于 2015-08-09T15:26:08.620 に答える
1

あなたの主な不満は についてfromJustですが、それがあなたの目標に根本的に反していることを考えると、なぜそれを使用しているのですか?

の最大の理由errorは、型システムが保証できる方法ですべてを定義できるわけではないということです。fromJust「コンパイラよりもよく知っていることもある」というこの考え方から来ています。その考え方に同意しない場合は、使用しないでください。または、この例のように悪用しないでください。

編集:

私の主張を拡張するには、求めているものをどのように実装するかを考えてください (部分関数の使用に関する警告)。次のコードのどこに警告が適用されますか?

a = fromJust $ Just 1
b = Just 2
c = fromJust $ c
d = fromJust
e = d $ Just 3
f = d b

結局、これらはすべて静的に部分的ではありません。(この次の構文がずれていたらすみません、遅くなりました)

g x = fromJust x + 1
h x = g x + 1
i = h $ Just 3
j = h $ Nothing
k x y = if x > 0 then fromJust y else x
l = k 1 $ Just 2
m = k (-1) $ Just 3
n = k (-1) $ Nothing

iここでも安全ですが、jそうではありません。警告を返すメソッドはどれですか? これらのメソッドの一部またはすべてが関数の外で定義されている場合、どうすればよいでしょうか。k条件付きで部分的な場合はどうしますか?これらの関数の一部またはすべてが失敗する必要がありますか?

コンパイラにこの呼び出しを行わせることで、多くの複雑な問題を混同しています。特に、ライブラリを慎重に選択することで回避できると考える場合はなおさらです。

どちらの場合でも、これらの種類の問題に対する IMO の解決策は、コンパイラを変更するのではなく、コンパイル後またはコンパイル中にツールを使用して問題を探すことです。このようなツールは、「あなたのコード」と「彼らのコード」をより簡単に理解し、不適切な使用について警告するのに最適な場所をより適切に判断できます。誤検出を避けるために、ソース ファイルに大量の注釈を追加することなく、チューニングすることもできます。手に負えないツールを知らないか、提案します。

于 2015-08-08T00:17:33.217 に答える