139

このキーワードが何をするかについての実際の説明を求めて、インターネットを精査しました。私が見たすべてのHaskellチュートリアルは、ランダムに使い始めただけで、それが何をするかを説明していません(そして私は多くを見てきました)。

を使用するReal World Haskellの基本的なコードを次に示しますJust。コードの機能は理解できますが、目的や機能がわかりませんJust

lend amount balance = let reserve    = 100
                      newBalance = balance - amount
                  in if balance < reserve
                     then Nothing
                     else Just newBalance

私が観察したことから、それはMaybeタイピングに関連していますが、それは私が何とか学んだすべてです.

何を意味するのかの良い説明はJust非常に高く評価されます。

4

5 に答える 5

241

実際には、すべてのモジュールに自動的にインポートされる標準ライブラリであるPreludeでたまたま定義されているのは、通常のデータ コンストラクターです。

Maybe とは、構造的に

定義は次のようになります。

data Maybe a = Just a
             | Nothing

その宣言は、Maybe a型変数によってパラメーター化される型を定義します。これはa、の代わりに任意の型で使用できることを意味しますa

構築と破壊

この型には 2 つのコンストラクターJust aNothing. 型に複数のコンストラクターがある場合、その型の値は可能なコンストラクターの 1 つだけで構築されている必要があることを意味します。このタイプの場合、値はJustまたはを介し​​て構築されNothingました。他の (エラー以外の) 可能性はありません。

パラメーターの型がないため、コンストラクターとして使用される場合、すべてNothingの型のメンバーである定数値に名前を付けます。ただし、コンストラクターには型パラメーターがあります。つまり、コンストラクターとして使用すると、型から型への関数のように機能します。つまり、型を持ちます。Maybe aaJustaMaybe aa -> Maybe a

したがって、型のコンストラクターはその型の値を構築します。物事の反対側は、その値を使用したい場合であり、パターン マッチングが機能する場所です。関数とは異なり、コンストラクターはパターン バインディング式で使用できます。これにより、複数のコンストラクターを持つ型に属する値の大文字と小文字の分析を行うことができます。

パターンマッチで値を使用するには、次Maybe aのように各コンストラクターにパターンを提供する必要があります。

case maybeVal of
    Nothing   -> "There is nothing!"
    Just val  -> "There is a value, and it is " ++ (show val)

その場合の式では、最初のパターンは値が の場合にNothing一致し、2 番目のパターンは値が で構築された場合に一致しJustます。2 番目のものが一致する場合は、一致する値が構築されたときにコンストラクターにval渡されたパラメーターにも名前をバインドします。Just

たぶん何を意味するのか

これがどのように機能するかについては、すでにご存知かもしれません。値にマジックはありませんMaybe。通常の Haskell Algebraic Data Type (ADT) です。しかし、あなたの例のように、値の欠如を表すInteger余分な値 ( ) を持つ新しいコンテキストに型を効果的に「持ち上げる」または拡張するため、かなり使用されています! Nothing次に、型システムでは、そこにある可能性のある にアクセスできるようにする前に、その余分な値をチェックする必要がIntegerあります。これにより、かなりの数のバグが防止されます。

今日の多くの言語は、この種の「値のない」値を NULL 参照を介して処理します。著名なコンピューター科学者であるトニー・ホーア (彼はクイックソートを発明し、チューリング賞の受賞者です) は、これを彼の「10 億ドルの間違い」として認めています。Maybe 型はこれを修正する唯一の方法ではありませんが、効果的な方法であることが証明されています。

多分 Functor として

ある型を別の型に変換して、古い型での操作を新しい型で機能するよう変換するという考え方は、 という Haskell 型クラスの背後にある概念でありFunctor、これMaybe aには の便利なインスタンスがあります。

Functorfmapは、基本型 ( などInteger) の値の範囲にある関数を、リフトされた型 ( など) の値の範囲にある関数にマップする というメソッドを提供しますMaybe Integer。値を操作するために で変換された関数は、次のようfmapに機能します。Maybe

case maybeVal of
  Nothing  -> Nothing         -- there is nothing, so just return Nothing
  Just val -> Just (f val)    -- there is a value, so apply the function to it

したがって、Maybe Integervaluem_xInt -> Intfunctionがある場合、実際に値があるかどうかを気にせずに、関数を に直接適用fできます。実際、持ち上げられた関数のチェーン全体を値に適用することができ、終了時に一度だけ明示的にチェックすることだけを気にする必要があります。fmap f m_xfMaybe IntegerInteger -> IntegerMaybe IntegerNothing

たぶんモナドとして

あなたが a の概念にどれだけ精通しているかはわかりMonadませんが、少なくともIO a以前に使用したことがあり、型シグネチャIO aは と非常によく似ていMaybe aます。IOコンストラクターを公開せず、Haskell ランタイム システムによってのみ「実行」できるという点で特別ですがFunctorMonad. Monad実際、 a はいくつかの特別な機能を備えた特別な種類の にすぎないという重要な意味がありFunctorますが、ここではそれについて説明する場所ではありません。

とにかく、モナドはIO型を「結果が値になる計算」を表す新しい型にマップするのが好きで、通常の関数を「値を評価することによって得られる計算」に変える非常に似た関数 Monadを介して、関数を型に持ち上げることができます。関数。"fmapliftM

あなたはおそらく(ここまで読んだなら)それMaybeMonad. 「値を返さない可能性のある計算」を表します。例と同様にfmap、これにより、各ステップの後で明示的にエラーをチェックすることなく、大量の計算を実行できます。実際、Monadインスタンスが構築される方法では、Maybe値の計算はa に遭遇するとすぐに停止するNothingため、計算の途中での即時の中止または値のないリターンのようなものです。

あなたはたぶん書いたかもしれません

前に言ったようにMaybe、言語構文またはランタイム システムに焼き付けられた型に固有のものは何もありません。Haskell がデフォルトで提供していない場合は、すべての機能を自分で提供できます。実際、別の名前を付けて自分で書き直して、同じ機能を得ることができます。

型とそのコンストラクタについては理解していただけたと思いますが、Maybe不明な点があればお知らせください。

于 2013-09-15T05:37:19.280 に答える
-1

関数はとif (cond :: Bool) then (ifTrue :: a) else (ifFalse :: a)の型が同じでなければなりません。ifTrueifFalse

したがって、 を記述するときは、 type inthen Nothingを使用する必要がありますMaybe aelse f

if balance < reserve
       then (Nothing :: Maybe nb)         -- same type
       else (Just newBalance :: Maybe nb) -- same type
于 2013-09-15T16:44:02.783 に答える