Edx Haskell courseMaybe
で、Erik Meijerは、失敗した計算に型を使用することはすべきことではないと繰り返し述べています。代わりに、空のリストを使用する必要があります。
私の理解では、Maybe
型は良いものであり、それを使用する必要があります。しかし、リストはモデル化できるものすべてをMaybe
モデル化できるようです...では、なぜMaybe
型が必要なのでしょうか?
Edx Haskell courseMaybe
で、Erik Meijerは、失敗した計算に型を使用することはすべきことではないと繰り返し述べています。代わりに、空のリストを使用する必要があります。
私の理解では、Maybe
型は良いものであり、それを使用する必要があります。しかし、リストはモデル化できるものすべてをMaybe
モデル化できるようです...では、なぜMaybe
型が必要なのでしょうか?
ただし、リストはすべてをモデル化できるようです
"and more" は、 を使用する優れた理由Maybe
です。リストのコンシューマとして、0、1、または複数の値を処理できる必要があります。の消費者として、Maybe
ゼロまたは 1 つの値を処理できる必要があるだけです。したがって、複数の値が意味をなさない場合はMaybe
、無意味な値を取得しないことを静的に知るために使用する方がはるかに優れています。
リストは、任意の数の結果をモデル化できます。一方、は結果を1 つだけモデル化するか、結果をMaybe
まったくモデル化しません。
次の関数について考えてみましょう。
f1 :: A -> [B]
f2 :: B -> [C]
f3 :: C -> [D]
f4 :: D -> [E]
f1
、f2
、f3
またはf4
返される要素の数は明確ではありません。では、それらを並べるとどうなるでしょうか。
f :: A -> [E]
f s = f1 s >>= f2 >>= f3 >>= f4
結果にはいくつの要素が含まれている必要がありますか? 1?ゼロ?誤って n^n (n ~ 入力長) 要素のリストを作成したのでしょうか?
ただし、計算で値が 1 つだけ返されるか、値がまったく返されない場合は、適切な型によって必要なすべての情報がすぐに得られます。
f1 :: A -> Maybe B
f2 :: B -> Maybe C
f3 :: C -> Maybe D
f4 :: D -> Maybe E
f :: A -> Maybe E
f s = f1 s >>= f2 >>= f3 >>= f4
それで、それはそれです。Meijer の声明に戻ります。
Erik Meijer は、失敗した計算に Maybe 型を使用することはすべきではないと繰り返し述べています。代わりに、空のリストを使用する必要があります。
追加の客観的理由がなければ、これは単なる個人的な好みです。fmap
よりも優れていることは誰にでも言えますmap
。それは私たちがやるべきことです。その時点で、あなたは私を信じるか、質問するかのどちらかです。彼が講義で明らかにしなかった場合は、直接彼に尋ねてください。
私はここで合唱団に参加し、彼の議論の詳細をすべて提示されない限り、Meijer の推薦を評価することはできないと言いたい. 私には簡単に思えます:
Maybe
0 または 1 の結果を返す関数に使用します。[]
0 個以上の結果を返す関数に使用します。listToMaybe :: [a] -> Maybe a
とmaybeToList :: Maybe a -> [a]
fromData.Maybe
を使用して、あるスタイルで記述された関数を別のスタイルで機能するように適合させることです。Maybe
またはを使用するかどうかの選択を遅らせたい場合は、またはクラス[]
を使用できます。Alternative
MonadPlus
ポイント 4 の例:
import Control.Applicative (pure, Alternative(..))
safeDiv :: (Alternative f, Fractional a, Eq a) => a -> a -> f a
safeDiv _ 0 = empty
safeDiv x y = pure (x / y)
{-
>>> safeDiv 5 2 :: Maybe Float
Just 2.5
>>> safeDiv 5 0 :: Maybe Float
Nothing
>>> safeDiv 5 2 :: [Float]
[2.5]
>>> safeDiv 5 0 :: [Float]
[]
-}
bothSqrt :: (Alternative f, Floating a) => a -> f a
bothSqrt x = let x' = sqrt x
in pure x' <|> pure (-x')
{-
>>> bothSqrt 5 :: Maybe Float
Just 2.236068
>>> bothSqrt 5 :: [Float]
[2.236068,-2.236068]
>>> bothSqrt 5 >>= flip safeDiv 2 :: Maybe Float
Just 1.118034
>>>> bothSqrt 5 >>= flip safeDiv 2 :: [Float]
[1.118034,-1.118034]
-}