すべての固定サイズのコンテナーは強力なモノイドのファンクターですか、その逆ですか?


9

Applicative型クラスは、型指定された機能のカテゴリにデカルトmonoidal構造を保持ずさんmonoidalファンクタを表します。

言い換えると(,)、モノイド構造を形成する正準同型が見られる場合:

-- Implementations left to the motivated reader
assoc_fwd :: ((a, b), c) -> (a, (b, c))
assoc_bwd :: (a, (b, c)) -> ((a, b), c)

lunit_fwd :: ((), a) -> a
lunit_bwd :: a -> ((), a)

runit_fwd :: (a, ()) -> a
runit_bwd :: a -> (a, ())

タイプクラスとその法則は、次のように書くこともできます。

class Functor f => Applicative f
  where
  zip :: (f a, f b) -> f (a, b)
  husk :: () -> f ()

-- Laws:

-- assoc_fwd >>> bimap id zip >>> zip
-- =
-- bimap zip id >>> zip >>> fmap assoc_fwd

-- lunit_fwd
-- =
-- bimap husk id >>> zip >>> fmap lunit_fwd

-- runit_fwd
-- =
-- bimap id husk >>> zip >>> fmap runit_fwd

同じ構造に関してoplaxモノイドであるファンクタがどのように見えるか疑問に思うかもしれません。

class Functor f => OpApplicative f
  where
  unzip :: f (a, b) -> (f a, f b)
  unhusk :: f () -> ()

-- Laws:

-- assoc_bwd <<< bimap id unzip <<< unzip
-- =
-- bimap unzip id <<< unzip <<< fmap assoc_bwd

-- lunit_bwd
-- =
-- bimap unhusk id <<< unzip <<< fmap lunit_bwd

-- runit_bwd
-- =
-- bimap id unhusk <<< unzip <<< fmap runit_bwd

定義や法律に含まれる種類について考えると、残念な真実が明らかになります。OpApplicative制約は具体的なものではありませんFunctor

instance Functor f => OpApplicative f
  where
  unzip fab = (fst <$> fab, snd <$> fab)
  unhusk = const ()

ただし、すべてのApplicativeファンクター(実際にはFunctor)は取るに足らないものではありますOpApplicativeが、Applicative弛緩とOpApplicative弛緩の間には必ずしも良い関係があるとは限りません。したがって、デカルトのモノイド構造に対して強力なモノイド関数を探すことができます。

class (Applicative f, OpApplicative f) => StrongApplicative f

-- Laws:
-- unhusk . husk = id
-- husk . unhusk = id
-- zip . unzip = id
-- unzip . zip = id

このタイプの唯一の住人() -> ()はの恒等関数なので、上記の最初の法則は簡単()です。

ただし、残りの3つの法則、つまりサブクラス自体は簡単ではありません。特に、すべてApplicativeがこのクラスの合法的なインスタンスであるとは限りません。

以下は、Applicative合法的なインスタンスを宣言できるファンクターですStrongApplicative

  • Identity
  • VoidF
  • (->) r
  • Monoid m => (,) m (回答を参照)
  • Vec (n :: Nat)
  • Stream (無限)

そしてここにApplicative私たちができないいくつかのsがあります:

  • []
  • Either e
  • Maybe
  • NonEmptyList

ここでのパターンは、ことを示唆しているStrongApplicativeクラスが意味であるFixedSizeクラス、「固定サイズ」*多重度という意味**の住民aの住民でf a固定されています。

これは、2つの推測として述べることができます。

  • Applicativeタイプ引数の要素の「固定サイズ」コンテナを表すものはすべて、StrongApplicative
  • StrongApplicativeの発生数aが変化する可能性のあるのインスタンスは存在しません

誰もがこれらの推測を​​否定する反例、またはそれらが真または偽である理由を実証するいくつかの説得力のある推論について考えることができますか?


*形容詞の「固定サイズ」を適切に定義していないことに気づきました。残念ながら、このタスクは少し循環的です。「固定サイズ」のコンテナの正式な説明は知りませんが、それを考え出そうとしています。StrongApplicativeこれまでの私の最善の試みです。

ただし、これが適切な定義であるかどうかを評価するには、比較する必要があります。ファンクターがその型引数の住人に関して特定のサイズまたは多重度を持つことの意味のいくつかの正式/非公式の定義を考えると、問題は、StrongApplicativeインスタンスの存在が固定サイズと変動サイズのファンクターを正確に区別するかどうかです。

既存の正式な定義を意識せずに、「固定サイズ」という言葉の使い方を直感に訴えています。しかし、誰かがファンクタのサイズに関する既存の形式主義をすでに知っStrongApplicativeており、それと比較できる場合は、はるかに優れています。

**「多重度」とは、ファンクターのコドメインタイプの生息地でファンクターのパラメータータイプの任意の要素が「いくつ」発生するかを大まかに意味します。これはせずファンクタが適用される特定のタイプに関して、ひいてはパラメータ・タイプのいずれかの特定の住民に関係なく。

これについて正確ではないため、コメントに混乱が生じたため、さまざまなファンクタのサイズ/多重度を次のように検討する例をいくつか示します。

  • VoidF:固定、0
  • Identity:固定、1
  • Maybe:変数、最小0、最大1
  • []:変数、最小0、最大無限
  • NonEmptyList:変数、最小1、最大無限
  • Stream:固定、無限
  • Monoid m => (,) m:固定、1
  • data Pair a = Pair a a:固定、2
  • Either x:変数、最小0、最大1
  • data Strange a = L a | R a:固定、1

コメントは詳細な議論のためのものではありません。この会話はチャットに移動しました
Samuel Liew

「固定サイズ」の考えられる定義の1つは、「表現可能」です。すべての表現可能なファンクタは、ここで説明されている意味で強力なアプリケーション(->) rです。
Daniel Wagner

@DanielWagnerからの強いアプリケーションを継承するには、同型写像以上のものが必要だと思います(->) r。強力な適用構造を維持するには、同型のコンポーネントが必要です。何らかの理由でRepresentable Haskellでは型クラスは、神秘的な持っているtabulate . return = return(実際にも、非モナドファンクタのために意味がありません)法律を、それは私たちがそれを言う必要条件の1/4与えtabulatezipモノイドの、適切なカテゴリの射ですが。他の3つは、あなたが要求しなければならない追加の法律です。
Asad Saeeduddin

申し訳ありませんが、それはする必要があります「tabulateindex...、適切なカテゴリの射ている」
アサドSaeeduddin

@AsadSaeeduddin法律でドキュメントに述べられている方法は奇妙に特定されているかもしれませんが、要求することreturnは深刻な問題ではないことが判明しました。cotraverse getConst . Constデフォルトの実装であるreturn/ pureの面でDistributivedistributives / representablesは実装が一意であることを、形状を固定しているため、と。
duplode

回答:


4
  • Applicativeタイプ引数の要素の「固定サイズ」コンテナを表すものはすべて、StrongApplicative
  • StrongApplicativeの発生数aが変化する可能性のあるのインスタンスは存在しません

誰もがこれらの推測を​​否定する反例、またはそれらが真または偽である理由を実証するいくつかの説得力のある推論について考えることができますか?

その最初の推測についてはよくわかりません。@ AsadSaeeduddinとの議論に基づいて証明するのは難しいようですが、2番目の推測は正しいです。理由を確認するには、StrongApplicative法律を検討してくださいhusk . unhusk == id。それはすべてのために、ですx :: f ()husk (unhusk x) == x。しかし、Haskellではunhusk == const ()、法律がすべての人に言えることと同じになるようにx :: f ()husk () == x。しかし、これは順番にしかないタイプの1つの異なる値を存在することを意味f ()二つの値があった場合:x, y :: f ()それから、x == husk ()husk () == yそう、x == y。ただし、可能なf ()値が1つしかfない場合は、固定形状でなければなりません。(例えばためdata Pair a = Pair a a、タイプの一つの値だけがあるPair ()、これはビーイングPair () ()が、複数種類の値が存在するMaybe ()か、または[()]。)したがってhusk . unhusk == idf固定形状でなければならないことを意味します。


うーん。派手なGADTなどが存在f ()する場合、「タイプの明確な値は1つしか存在できない」ということは、「発生するa可能性のある数は変化しない」ことを意味することは本当に明らかですか?
Daniel Wagner

@DanielWagner「発生回数のa変動は不可能」はStrongApplicativeインスタンスにとって十分な条件ではないことが判明しました。たとえば、のdata Writer w a = Writer (w,a)多様性は変化しaませんが、ではありませんStrongApplicative。ファンクターの形は不変である必要がありますが、これはf ()シングルトンであることの結果だと私は信じています。
Bradrn

それがどのように関連しているかはわかりません。その答えでは、2番目の推測を確認しながら、「強い適用」が「1つの明確なf ()」が「a変化できない発生の数」を意味することを意味すると主張します。私はその議論の最後のステップが明らかに真実ではないことに反対しています。例を考えてくださいdata Weird a where One :: a -> Weird a; None :: Weird Bool。typeには明確な値がありますが、Weird ()コンストラクターによってasの数が異なります。(Functor難しいので、これは完全な反例ではありませんが、修正できないことをどうやって知ることができますか?)
Daniel Wagner

@DanielWagner Weird ()シングルトンは良い点ですが、形状は固定されていません。しかし、WeirdではないFunctorので、それはすることはできません、StrongApplicativeとにかく。:私は、関連する推測のようになりますと仮定した場合fFunctor、んf ()シングルトンであることはそれが意味するものではf固定形状でありますか?私はこれが真実であると強く疑っていますが、あなたが指摘したように、私は実際にはまだ証拠がありません。
Bradrn

5

私たちはこれらの質問の少なくとも1つに否定的に答えることができます。

タイプ引数の要素の「固定サイズ」コンテナを表すすべてのApplicativeは、StrongApplicativeのインスタンスです

実際StrongApplicative、元の質問の合法的な例の1つは間違っています。たとえば、作家のアプリケーションMonoid => (,) mはそうStrongApplicativeではありませんhusk $ unhusk $ ("foo", ()) == ("", ()) /= ("foo", ())

同様に、固定サイズのコンテナの例:

data Strange a = L a | R a

固定された多重度1は強い適用ではありません。なぜなら、私たちがhusk = Leftthen を定義するhusk $ unhusk $ Right () /= Right ()と、その逆も同様だからです。これを表示する同等の方法は、これは、上のモノイドの選択に適用できる単なるライターであることですBool

したがって、「固定サイズ」ではないアプリケーションが存在しますStrongApplicative。すべてStrongApplicativeのが固定サイズであるかどうかは不明です。


5

「固定サイズのコンテナ」の定義として、表現可能なファンクタを取り上げましょう。

class Representable f where
    type Rep f
    tabulate :: (Rep f -> a) -> f a
    index :: f a -> Rep f -> a

実際Representableにはいくつかの法則とスーパークラスがありますが、この答えの目的のために、実際には2つのプロパティだけが必要です。

tabulate . index = id
index . tabulate = id

(さて、私たちは法律を遵守することも必要instance StrongApplicative ((->) r)です。簡単なことです、あなたはそれが存在することにすでに同意しています。)

その定義を採用すると、予想1が確認できます。

Applicativeタイプ引数の要素の「固定サイズ」コンテナを表すものはすべて、[法則]のインスタンスです。StrongApplicative

本当です。方法は次のとおりです。

instance Representable f => Applicative f where
    zip (fa, fb) = tabulate (zip (index fa, index fb))
    husk = tabulate . husk

instance Representable f => OpApplicative f where
    unzip fab = let (fa, fb) = unzip (index fab) in (tabulate fa, tabulate fb)
    unhusk = unhusk . index

instance Representable f => StrongApplicative f

そこ証明するための法律の多くのですが、私は四大に、ちょうどその焦点を当てますStrongApplicativeアドオンを-あなたはおそらくすでにリードイン用のものを信じているApplicativeOpApplicative、しかし、そうでない場合は、その証明はちょうど下記のもののように見えます(これは、互いに非常によく似ています)。明確にするために、私が使用するzipfhuskf関数インスタンスのための、およびなど、ziprhuskr表現例えば、など、あなたがしているのを追跡することができます。(そして、証明しようとしていることを仮定として受け取らないことを簡単に確認できるように!を証明するunhuskf . huskf = idときに使用してunhuskr . huskr = idも問題ありませんunhuskr . huskr = idが、同じ証明で仮定するのは間違っています。)

各法則の証明は、基本的に同じ方法で行われます。定義を展開し、Representable得られる同型を取り除き、関数に類似の法則を使用します。

unhuskr . huskr
= { def. of unhuskr and huskr }
(unhuskf . index) . (tabulate . huskf)
= { index . tabulate = id }
unhuskf . huskf
= { unhuskf . huskf = id }
id

huskr . unhuskr
= { def. of huskr and unhuskr }
(tabulate . huskf) . (unhuskf . index)
= { huskf . unhuskf = id }
tabulate . index
= { tabulate . index = id }
id

zipr (unzipr fab)
= { def. of unzipr }
zipr (let (fa, fb) = unzipf (index fab) in (tabulate fa, tabulate fb))
= { def. of zipr }
let (fa, fb) = unzipf (index fab) in tabulate (zipf (index (tabulate fa), index (tabulate fb)))
= { index . tabulate = id }
let (fa, fb) = unzipf (index fab) in tabulate (zipf (fa, fb))
= { def. of (fa, fb) }
tabulate (zipf (unzipf (index fab)))
= { zipf . unzipf = id }
tabulate (index fab)
= { tabulate . index = id }
fab

unzipr (zipr (fa, fb))
= { def. of zipr }
unzipr (tabulate (zipf (index fa, index fb)))
= { def. of unzipr }
let (fa', fb') = unzipf (index (tabulate (zipf (index fa, index fb))))
in (tabulate fa', tabulate fb')
= { index . tabulate = id }
let (fa', fb') = unzipf (zipf (index fa, index fb))
in (tabulate fa', tabulate fb')
= { unzipf . zipf = id }
let (fa', fb') = (index fa, index fb)
in (tabulate fa', tabulate fb')
= { def. of fa' and fb' }
(tabulate (index fa), tabulate (index fb))
= { tabulate . index = id }
(fa, fb)

現在考えている:instance StrongApplicative f => Representable f where type Rep f = forall x. f x -> xindexは簡単だ。私はtabulateまだそのトリックを解決していませんが、食欲をそそるほど近いようです。
ダニエルワグナー

@AsadSaeeduddinとの話し合いで、私はこれと同じStrongApplicativeインスタンスを何とか見つけましたが、法律を証明できませんでした。おめでとうございます!私Representableも与えられたインスタンスを実行しようとしましたStrongApplicativeが、良いRepタイプを考えることができませんでした。知りたいのですが、どうやってforall x. f x -> xこれを実現しますか?
Bradrn

@bradrn仮説は、これらのものには要素が挿入される「穴」の固定セットがあるということを思い出してください。次に、typeの関数はforall x. f x -> x、まさにホールを選択してそのホールの値を返す関数です。(そして、を実装する方法について考えている間tabulateに、のタイプに異議を唱えましたunhusk。詳細については、質問自体のコメントを参照してください。)
Daniel Wagner

@DanielWagner、ありがとう!それは本当に賢いアプローチです—私はそのことを考えなかったでしょう。
Bradrn

それを実装しようとした後、私はそれforall x. f x -> xがとして機能すると確信しているとは思いませんRep。私の推論では、これを使用するとRep、タイプだけでなくindexあらゆるタイプの書き込みStrongApplicativeforall x. f x -> x可能になるため、一般的すぎると思われます。
Bradrn
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.