「null」と「Maybe」の両方の概念を持つことは意味がありますか?


11

C#でWeb APIのクライアントを作成しているときに、null2つの異なるものを表す値として問題が発生しました。

  • 何もありません。たとえばfoobar
  • 不明:デフォルトでは、API応答にはプロパティのサブセットのみが含まれます。必要な追加のプロパティを指定する必要があります。したがって、不明とは、プロパティがAPIからリクエストされなかったことを意味します。

Maybe(またはOption)タイプ、関数型言語での使用方法、およびユーザーに値の不在について考えさせることによりnull逆参照の問題を「解決」する方法について調べたところ、次のことがわかりました。しかし、私が遭遇したすべてのリソースはnullMaybeで置き換えることについて話しました。私は3値的論理についての言及をいくつか見つけましたが、私はそれを完全には理解していません。ほとんどの場合、その言及は「それは悪いこと」の文脈で行われていました。

nullMaybeの両方の概念を持ち、それぞれ未知数何も表現しないことが理にかなっているのではないかと思っています。これは私が読んだ3値論理ですか、それとも別の名前ですか?または、多分多分に多分をネストするための意図された方法ですか?


9
持っているのはサンスにはなりませんnull。それは完全に壊れた考えです。
Andrej Bauer 2016

7
maybe-fooとは異なるセマンティクスを持つmaybe-maybe-fooを作成しないでください。多分モナドであり、モナドの法則の1つはそれでM M xありM x、同じセマンティクスを持つべきです。
Eric Lippert、2016

2
何もない(オブジェクトへの参照がない)、Null(データベースのnullセマンティクス)、Empty(初期化されていない変数)、Missing(オプションのパラメーターが渡されなかった)があったVisual Basicの初期バージョンのデザインを検討することを検討してください。この設計は複雑で、多くの点で一貫性がありませんでしたが、それらの概念が相互に統合されなかったのには理由があります。
Eric Lippert、2016

3
はい、多分多分使用しないでしょう。しかし、実際には、同じようにMaybe a同じである、意味的に、同じである、及び同型@Andejの答えから入力します。この型のために独自のモナドインスタンスを定義することもできるため、異なるモナドコンビネータを使用できます。a + 1 + 1a+1Maybe Maybe aa+1+1UserInput a
2016

12
@EricLippert:それは偽である「M (M x)M x同じ意味を持つべきです」。テイクM = List例えば:リストのリストは、リストと同じものではありません。Mがモナドである場合、それらの間の関係を説明する変換(つまりモナド乗算)M (M x)M xありますが、それらには「同じセマンティクス」はありません。
Andrej Bauer 2016

回答:


14

nullどこにでも存在するデフォルトとしての値は、本当に壊れたアイデアなので、忘れてください。

実際のデータを最もよく表す概念を常に正確に持っている必要があります。「不明」、「なし」、「値」を示すタイプが必要な場合は、それが必要です。しかし、それが実際のニーズに合わない場合は、実行しないでください。他の人々が何を使っているか、彼らが提案したものを見ることは良い考えですが、あなたは彼らを盲目的にフォローする必要はありません。

標準ライブラリを設計する人々は、一般的な使用パターンを推測しようとしますが、通常はそれをうまく行いますが、必要な特定の事項がある場合は、自分で定義する必要があります。たとえば、Haskellでは、次のように定義できます。

data UnknownNothing a =
     Unknown
   | Nothing
   | Value a

覚えやすい、より説明的なものを使用する必要がある場合もあります。

data UserInput a =
     Unknown
   | NotGiven
   | Answer a

さまざまなシナリオで使用される10のタイプを定義できます。欠点は、既存のライブラリ関数(などのものMaybe)を利用できないことですが、通常はこれが詳細です。独自の機能を追加することはそれほど難しくありません。


あなたがそれがそのように綴られているのを見るとき、完全に理にかなっています。私は主にアイデアに興味があります。既存のライブラリサポートは単なるボーナスです:)
Stijn

多くの言語でそのようなタイプを作成するための障壁が低くなった場合。:/
ラファエル

1960年代から言語の使用をやめた場合(または1980年代から生まれ変わった場合)。
Andrej Bauer 2017年

@AndrejBauer:なに?しかし、理論家は何も文句を言うことはありません!
イットリル2017年

私たちは文句を言わないで、私たちは高所にいます。
Andrej Bauer

4

私の知る限りnull、C#の値は、その型に応じて、一部の変数で使用できる値です(私は正しいですか?)。たとえば、いくつかのクラスのインスタンス。残りのタイプ(、など)intではbool、変数をint?またはで宣言することにより、この例外値を追加できますbool?(これはMaybe、次に説明するように、コンストラクターが行うこととまったく同じです)。

Maybe関数型プログラミングの型コンストラクタは、指定されたデータ型にこの新しい例外値を追加します。したがって、Intが整数のタイプまたはGameゲームの状態のタイプである場合、Maybe Intはすべての整数に加えてnullもとは呼ばれない)値を持ちます。も同じですMaybe Game。ここでは、null値を伴うタイプはありません。必要なときに追加します。

IMO、この最後のアプローチは、どのプログラミング言語にも適しています。


はい、C#の理解は正しいです。だからあなたはあなたの答えから推測して、あなたはMaybesを入れ子にしてnull完全に落とすことを勧めますか?
Stijn、

2
私の意見は、言語がどうあるべきかについてです。C#プログラミングのベストプラクティスは本当にわかりません。あなたの場合、最良のオプションは@Andrej Bauerが説明するようにデータ型を定義することですが、C#ではそれを実行できないと思います。
16

@Euge:代数和型は、古典的なOOスタイルのサブタイピングとサブタイプのポリモーフィックメッセージディスパッチで(大まかに)近似できます。これがScalaで行われる方法であり、たとえば、クローズド型を可能にするために追加の工夫が施されています。型は抽象スーパークラスになり、型コンストラクターは具象サブクラスになり、コンストラクターに対するパターンマッチングは、具象サブクラスまたはisinstanceテストでオーバーロードされたメソッドにケースを移動することによって概算できます。Scalaには「適切な」パターンマッチングもあり、C♯も実際に最近単純なパターンを獲得しました。
イェルクWミッターク

私がScalaについて述べた「追加のひねり」は、「標準」修飾子「仮想」(継承可能なクラスの場合)およびfinal(継承できないクラスの場合)に加えてsealed同じコンパイル単位内でのみ拡張できるクラス。これは、コンパイラーがすべての可能なサブクラスを静的に認識できることを意味し(それらすべてが自身sealedまたはのいずれかである場合final)、パターンの一致を網羅的にチェックします。
イェルクWミッターク

もちろん、C#でそれらのセマンティクスを使用して型を設計できます。C#では、組み込みの多分型(C#ではNullableと呼ばれます)を入れ子にできないことに注意してください。 int??C#では不正です。
Eric Lippert、2016

3

のような型共用体を定義でき、値だけを表す(それ以外は何もない)X or Yという名前の型がある場合、どの型についても、実際にはとそれほど違いはありません。唯一の問題は、言語が型を暗黙的に扱い、すべての型に対して有効な値を作成する場合です(それらの型を持つ言語のプリミティブ型を除く)。これは、たとえば、Java でも発生します。NullnullTT or NullMaybe TnullTT or NullnullStringnull

タイプを値orのセットおよび集合の和集合として扱う場合、は値のセットを(T or Null) or Null表しますT ∪ {null} ∪ {null}。これはと同じT or Nullです。この種の分析(SBCL)を実行するコンパイラーがあります。コメントで言ったように、あなたは簡単に区別することはできませんMaybe Tし、Maybe Maybe Tあなたがドメインとしてのタイプを表示したときに(一方で、そのビューは動的型付けのプログラムのために非常に便利です)。ただし、型を代数表現として保持することもできます(T or Null) or Null。ここで、は多レベルの複数のレベルを表します。


2
実際、とMaybe (Maybe X)同じではないことが重要ですMaybe XNothingと同じではありませんJust Nothing。と衝突するMaybe (Maybe X)Maybe XMaybe _多態性を扱うことができなくなります。
Gilles「SO-邪悪なことをやめよ」

1

表現したいものを見つけ、それを表現する方法を見つける必要があります。

まず、問題のドメインに値があります(数値、文字列、顧客レコード、ブール値など)。次に、問題のドメイン値に加えて、いくつかの追加の一般的な値があります。たとえば、「nothing」(値の既知の不在)、「unknown」(値の存在または不在に関する知識がない)、言及されていないなど何か」(確かに価値はありますが、どれがいいかわかりません)。多分あなたは他の状況を考えることができます。

すべての値とこれらの3つの追加値を表すことができるようにしたい場合は、「nothing」、「unknown」、「something」、および「value」のケースを持つ列挙を作成し、そこから移動します。

一部の言語では、場合によってはより単純です。たとえば、Swiftでは、すべてのタイプTに対して、可能な値としてnilとすべてのTの値を持つ「オプションのT」タイプがあります。これにより、多くの状況を簡単に処理でき、「なし」と「値"。「不明」と「値」がある場合に使用できます。「なし」、「不明」、「値」を処理する必要がある場合使用できません。他の言語では「null」または「たぶん」を使用する場合がありますが、それは単なる別の言葉です。

JSONには、キーと値のペアを持つ辞書があります。ここでは、キーがディクショナリから欠落しているか、値がnullである可能性があります。したがって、物事がどのように格納されるかを注意深く説明することにより、一般的な値と2つの追加の値を表すことができます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.