13

ユーザー「singpolyma」はredditで、基礎となる一般的な構造があるかどうかを尋ねました。

data FailList a e = Done | Next a (FailList a e) | Fail e

無料のモナドが提案されましたが、これはアプリケーションファンクターを介してより一般的にモデル化できるのではないかと思いました。Abstracting with Applicativesで、Bazermanは、バイアスの方向に自然変換があれば、2つのApplicativeファンクターの合計もApplicativeファンクターであり、左右にバイアスがあることを示しています。これは私たちが必要としているもののように聞こえます!したがって、私は提案を始めましたが、すぐに問題にぶつかりました。誰かがこれらの問題の解決策を見ることができますか?:


まず、2つのファンクターの合計の定義から始めます。ここから始めたのは、成功または成功と失敗の合計タイプをモデル化するためです。

data Sum f g a = InL (f a) | InR (g a)

そして、私たちが使用したい2つのファンクターは次のとおりです。

data Success a = Success [a]
data Failure e a = Failure e [a]

Success簡単です-それは本質的にConst [a]です。しかし、Failure eよくわかりません。pure定義がないため、これは適用可能なファンクターではありません。ただし、これはApplyのインスタンスです。

instance Functor Success where
  fmap f (Success a) = Success a

instance Functor (Failure e) where
  fmap f (Failure e a) = Failure e a

instance Apply (Failure e) where
  (Failure e a) <.> (Failure _ b) = Failure e a

instance Apply Success where
  (Success a) <.> (Success b) = Success (a <> b)

instance Applicative Success where
  pure = const (Success [])
  a <*> b = a <.> b

次に、これらのファンクターの合計を、右から左への自然変換(つまり左バイアス)で定義できます。

instance (Apply f, Apply g, Applicative g, Natural g f) => Applicative (Sum f g) where
  pure x = InR $ pure x
  (InL f) <*> (InL x) = InL (f <*> x)
  (InR g) <*> (InR y) = InR (g <*> y)
  (InL f) <*> (InR x) = InL (f <.> eta x)
  (InR g) <*> (InL x) = InL (eta g <.> x)

そして今私たちがしなければならない唯一のことは私たちの自然変換を定義することです、そしてこれはそれがすべて崩壊するところです。

instance Natural Success (Failure e) where
  eta (Success a) = Failure ???? a

を作成できないことFailureが問題のようです。さらに、ハッキーで⊥を使用することもオプションではありません。これは、を持っている場合に評価されるためInR (Success ...) <*> InL (Failure ...)です。

何かが足りないような気がしますが、それが何なのかわかりません。

これはできますか?

4

2 に答える 2

5

eあなたがredditの議論でそのアイデアを嫌ったのと同じように、「正しい」答えはモノイドを作ることだと私はかなり確信しています。

Failure "oops" [(*1),(*2),(*3)] <*> Failure "doh" [1,2,3]結果に失敗として「oops」または「doh」を含める必要があるかどうかを検討してください。モノイドを作ることeで、標準的な選択がないという事実を捉え、消費者に毒を選ばせます(First、、、Lastなど[]

このソリューションは、(Maybe e, [a])表現と同様に、ストリーミング/潜在的に無限のデータを正しく処理しないことに注意してください。これは、リストの終了に失敗したかどうかが厳密であるためです。

別のエンコーディングでは、フォローアップの投稿( http://comonad.com/reader/2013/algebras-of-applicatives/ )に従って、Applicativeのフィックスポイントを使用します。

次に、そこに表示されているリスト表現(FixF (ProductF Embed (Sum (Const ()))) a)を取得し、エラーモノイドをユニットの位置に貼り付けて変更すると、次のようになります。

Monid mon => FixF (ProductF Embed (Sum (Const mon))) a

Maybeまた、モノイドの代わりに正確にを取得するために使用できることに注意してください。ただし、エラーを組み合わせる正しい方法を指定するインスタンスを作成しない限りFailList、同じようFailListに無料でアプリケーションインスタンスを取得することはできません。

また、不動点アプローチでは、Success [(*1),(*2),(*3)] <*> Failure "doh" [1,2,3,4,5]それに相当するものがある場合、3つの要素でaがSuccess返されますが(つまり、失敗は完全に厳密ではありません)、提案するアプローチでは、3つの要素でaが返さFailureれ、5つの要素からエラーが返されます。要素の失敗リスト。これは、ストリーミングと厳密のトレードオフです。

最後に、そして最も簡単に言えば、type FailList e = Product (Const (First e)) ZipList標準のアプリケーション機構を使用して、元のデータ型に非常に近いものを取得することができます。

于 2013-03-21T20:35:53.227 に答える
2
{-# LANGUAGE FlexibleInstances #-}

instance Applicative (Sum Success (Failure e)) where
  pure x = InL $ pure x
  (InL f) <*> (InL x) = InL (f <*> x)
  (InR (Failure e fs)) <*> (InR (Failure _ gs)) = InR (Failure e (fs <*> gs))
  (InR (Failure e fs)) <*> (InL (Success gs)) = InR (Failure e (fs <*> gs))
  (InL (Success gs)) <*> (InR (Failure e fs)) = InR (Failure e (gs <*> fs))

これは、成功のリストにいつでも失敗を追加できるためです;)

代わりにこの型クラスを使用することもできますNatural f g

class Transplant f g where
  transplant :: f a -> g b -> f b

instance Transplant (Failure e) Success where
  transplant (Failure e _) (Success a) = Failure e a

圏論的にそれが何を意味するのか分かりません。

于 2013-03-17T17:12:24.000 に答える