14

私はhaskellの初心者で、Learn youahaskellの本を読んでいます。私はしばらくの間、ファンクターとアプリケーションファンクターを消化しようとしています。

適用可能なファンクターのトピックでは、のインスタンス実装Maybeは次のように与えられます。

instance Applicative Maybe where
  pure = Just
  Nothing <*> _ = Nothing
  (Just f) <*> something = fmap f something

ですから、私が理解しているNothingように、左側のファンクター(for <*>)がNothingであるかどうかがわかります。私には、それはより理にかなっているようです

  Nothing <*> something = something

そのため、このアプリケーションファンクターは効果がありません。配給のユースケースはありNothingますか?

言ってやるが、Maybe String私にはその価値がわからない。これをサードパーティの関数に渡す必要がありMaybeますが、その結果をMaybe (a -> b)最初に数回実行する必要があります。これらの関数のいくつかがあれば、データの損失であるをNothing与えるのではなく、サイレントに入力を返すようにします。Nothing

Nothingそれで、上記の例で戻ることの背後にある考え方は何ですか?

4

4 に答える 4

15

それはどのように機能しますか?型アノテーションは次のとおりです。

(<*>) :: Applicative f => f (a -> b) -> f a -> f b

したがって、ここでの2番目の引数はタイプMaybe aであり、結果はタイプである必要がありますMaybe baに変換する方法が必要です。bこれは、最初の引数が。でない場合にのみ実行できますNothing

このようなものが機能する唯一の方法は、typeの値が1つ以上あり、そうでない値Maybe (a -> a)を適用したい場合Nothingです。しかし、それはの一般的な定義にはあまりにも具体的です(<*>)


編集:Maybe (a -> a)それはあなたが実際に気にかけているシナリオのように思われるので、ここにそのタイプの値の束で何ができるかのいくつかの例があります:

すべての関数を保持し、sを破棄してNothingから、それらを適用します。

applyJust :: [Maybe (a -> a)] -> a -> a
applyJust = foldr (.) id . catMaybes

この関数は、値catMaybesのみを含むリストを提供し、恒等関数(適用する関数がない場合に取得されるもの)から始めて、それらをすべてまとめて構成します。Justfoldr

または、を見つけるまで関数を実行してNothingから、ベイルアウトすることもできます。

applyWhileJust :: [Maybe (a -> a)] -> a -> a
applyWhileJust (Just f:fs) = f . applyWhileJust fs
applyWhileJust (Nothing:_) = id

Nothingこれは、リストの残りの部分を無視することを除いて、上記と同様のアイデアを使用します。必要に応じて、次のように書くこともできますが、それapplyWhileJust = foldr (maybe (const id) (.)) idは少し読みにくいです...

于 2011-12-25T03:45:01.453 に答える
8

<*>を通常の*演算子と考えてください。a * 0 == 0、 右?何でも構いませんa。したがって、同じロジックを使用して、Just (const a) <*> Nothing == NothingApplicative法律では、データ型はこのように動作する必要があると規定されています。

これが役立つ理由は、何かが存在しないことではなく、何かが存在Maybeすることを表すことになっているからです。関数のチェーンを介して値をパイプライン処理する場合、1つの関数が失敗すると、失敗が発生したことを意味し、プロセスを中止する必要があります。Maybe

提案する動作には多くの問題があるため、実用的ではありません。

  1. 失敗した関数が入力を返す場合、a -> a関数の結果に応じて戻り値と入力値を交換できるようにするには、戻り値と入力値が同じ型である必要があるため、型が必要です。
  2. あなたの論理によると、あなたが持っている場合はどうなりますJust (const 2) <*> Just 5か?この場合の動作をどのようにしてケースと一致させることができNothingますか?

法律も参照してApplicativeください。

編集:コードのタイプミスを修正しました。

于 2011-12-25T03:49:09.647 に答える
3

さて、これはどうですか?

Just id <*> Just something

<*>を使用して複数の入力を持つ関数を調べ始めると、Nothingのユースケースが発生します。

(-) <$> readInt "foo" <*> readInt "3"

関数があるとするとreadInt :: String -> Maybe Int、これは次のようになります。

(-) <$> Nothing <*> Just 3

<$>fmap、でfmap f NothingありNothing、であるため、次のようになります。

Nothing <*> Just 3

なぜこれが何も生成しないのかわかりますか?式の本来の意味は2つの数値を減算することでしたが、最初の入力後に部分的に適用された関数を生成できなかったため、減算とは関係のない優れた関数を作成するのではなく、その失敗を伝播する必要があります。

于 2011-12-25T11:39:00.903 に答える
1

CAマッキャンの優れた回答に加えて、これは「無料の定理」の場合である可能性があることを指摘したいと思います。http://ttic.uchicago.edu/~dreyer/course/papers/wadler.pdfを参照してください。このホワイトペーパーの要点は、一部のポリモーフィック関数では、特定の型アノテーションに対して可能な実装は1つだけであるということです。たとえば、ペアの最初の要素を返す(または未定義)以外に選択肢fst :: (a,b) -> aはありません。これは証明できます。このプロパティは直感に反しているように見えるかもしれませんが、関数がその多態的な引数について持っている非常に限られた情報に根ざしています(特に、薄い空気から1つを作成することはできません)。

于 2011-12-25T12:57:51.743 に答える