Tüm sabit boyutlu kaplar güçlü monoidal functorlar mı ve / veya tersi mi?


9

ApplicativeTypeclass temsil gevşek monoidal fanktorlar o yazdığınız fonksiyonları kategorisine kartezyen monoidal yapısını korumak.

Başka bir deyişle, (,)monoidal bir yapı oluşturan tanık kanonik izomorfizmlere bakıldığında :

-- 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, ())

Typeclass ve yasaları aynı şekilde şu şekilde yazılabilir:

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

Aynı yapıya göre oplax monoidal olan bir functor'un nasıl görünebileceği merak edilebilir :

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

Tanımlara ve yasalara dahil olan türleri düşünürsek, hayal kırıklığı yaratan gerçek ortaya çıkar; OpApplicativeaşağıdakilerden daha belirgin bir kısıtlama değildir Functor:

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

Bununla birlikte, her Applicativeişlev (gerçekten, herhangi bir Functor) önemsiz OpApplicativeolsa da, Applicativegevşeklik ve OpApplicativeoplaksite arasında mutlaka güzel bir ilişki yoktur. Böylece kartezyen monoidal yapı ile güçlü monoidal functorlar arayabiliriz :

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

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

Yukarıdaki ilk yasa önemsizdir, çünkü türün tek sakini () -> ()kimlik işlevidir ().

Ancak, geri kalan üç yasa ve dolayısıyla alt sınıfın kendisi önemsiz değildir . Özellikle, her Applicativebiri bu sınıfın yasal bir örneği değildir .

İşte Applicativeyasal örneklerini beyan edebileceğimiz bazı işlevler StrongApplicative:

  • Identity
  • VoidF
  • (->) r
  • Monoid m => (,) m (cevaplara bakınız)
  • Vec (n :: Nat)
  • Stream (sonsuz)

Ve işte Applicativeyapamayacağımız bazı s:

  • []
  • Either e
  • Maybe
  • NonEmptyList

Buradaki desen, StrongApplicativesınıfın bir anlamda FixedSizesınıf olduğunu gösterir, burada "sabit boyut" * , bir sakinte yaşayanların çokluğunun ** sabit olduğu anlamına gelir .af a

Bu iki varsayım olarak ifade edilebilir:

  • ApplicativeKendi tür argümanındaki öğelerin "sabit boyutlu" bir kabını temsil eden her biri,StrongApplicative
  • StrongApplicativeOluşma sayısının adeğişebileceği hiçbir örnek yoktur.

Herkes bu varsayımları çürüten karşı örnekleri ya da neden doğru ya da yanlış olduklarını gösteren ikna edici bir akıl yürütmeyi düşünebilir mi?


* "Sabit boyut" sıfatını doğru tanımlamamışım. Ne yazık ki görev biraz dairesel. "Sabit boyutlu" bir konteynerin herhangi bir resmi tanımını bilmiyorum ve bir tane bulmaya çalışıyorum. StrongApplicativeşimdiye kadarki en iyi girişimim.

Bununla birlikte, bunun iyi bir tanım olup olmadığını değerlendirmek için, karşılaştırılacak bir şeye ihtiyacım var. Bir işlevin, tür argümanında yaşayanlara göre belirli bir boyuta veya çokluğa sahip olmasının ne anlama geldiğine dair bazı resmi / gayri resmi bir tanım verildiğinde, soru, bir StrongApplicativeörneğin varlığının sabit ve değişken büyüklükteki işlevleri kesin olarak ayırt edip etmediğidir .

Mevcut bir resmi tanımın farkında olmadan, "sabit boyut" terimini kullanmamda sezgiye itiraz ediyorum. Bununla birlikte, birisi zaten bir fontörün büyüklüğü için mevcut bir formalizmi biliyorsa ve StrongApplicativeonunla kıyaslayabilirse , çok daha iyi.

** "Çokluk" ifadesiyle, gevşek bir şekilde, functor'ın codomain türünün bir sakininde functor'ın parametre tipindeki keyfi öğelerin "kaç" olduğunu ifade ediyorum. Bu olmadan funktor uygulanır belirli bir tipine ilişkin olarak, ve bu nedenle parametre türü belirli herhangi bir sakinlerine bakılmaksızın.

Bu konuda kesin olmamak yorumlarda karışıklığa neden oldu, bu yüzden çeşitli functorların boyutunu / çokluğunu dikkate alacağımın bazı örnekleri:

  • VoidF: sabit, 0
  • Identity: sabit, 1
  • Maybe: değişken, minimum 0, maksimum 1
  • []: değişken, minimum 0, maksimum sonsuz
  • NonEmptyList: değişken, minimum 1, maksimum sonsuz
  • Stream: sabit, sonsuz
  • Monoid m => (,) m: sabit, 1
  • data Pair a = Pair a a: sabit, 2
  • Either x: değişken, minimum 0, maksimum 1
  • data Strange a = L a | R a: sabit, 1

Yorumlar uzun tartışmalar için değildir; bu sohbet sohbete taşındı .
Samuel Liew

"Sabit boyut" un olası bir tanımı "temsil edilebilir" olacaktır. Temsil edilebilir tüm işlevler burada açıklanan anlamda güçlü uygulamalardır, çünkü (->) rbunlar doğru şekilde izomorfiktir.
Daniel Wagner

@DanielWagner Bence güçlü uygulamayı miras almak için sadece bir izomorfizmden daha fazlasına ihtiyacınız var (->) r; güçlü uygulama yapısını korumak için izomorfizmin bileşenlerine ihtiyacınız vardır. Herhangi bir nedenle RepresentableHaskell'deki tip sınıfının gizemli bir tabulate . return = returnyasası var (monadik olmayan functors için gerçekten mantıklı bile değil), ancak bunu söylememiz gereken koşulların 1 / 4'ünü veriyor tabulateve zipuygun bir monoid kategorisinin morfizmleri. . Diğer üçü ise talep etmeniz gereken ekstra yasalardır.
Asad Saeeduddin

Üzgünüz, bu " tabulateve indexuygun bir kategorinin morfizmleri ..." olmalıdır
Asad Saeeduddin

@AsadSaeeduddin Belgelerde yasanın ifade biçimi garip bir şekilde belli olabilir, ancak zorunluluk ortaya çıkması returnciddi bir sorun değildir. cotraverse getConst . Const, return/ pureaçısından varsayılan bir uygulamadır Distributiveve dağıtımcılar / temsil edilebilirler sabit bir şekle sahip olduğundan, bu uygulama benzersizdir.
duplode

Yanıtlar:


4
  • Her ApplicativeKendi tür argümanındaki öğelerin "sabit boyutlu" bir kabını temsil eden biri,StrongApplicative
  • StrongApplicativeOluşma sayısının adeğişebileceği hiçbir örnek yoktur.

Herkes bu varsayımları çürüten karşı örnekleri ya da neden doğru ya da yanlış olduklarını gösteren ikna edici bir akıl yürütmeyi düşünebilir mi?

Bu ilk varsayımdan emin değilim ve @AsadSaeeduddin ile yapılan tartışmalara dayanarak kanıtlamak zor olabilir, ancak ikinci varsayım doğrudur. Nedenini görmek için StrongApplicativekanunu düşünün husk . unhusk == id; hepsi için vardır x :: f (), husk (unhusk x) == x. Ama Haskell, unhusk == const (), böylece yasa herkes için diyerek eşdeğerdir x :: f (), husk () == x. Ama sırayla bu sadece orada türden bir ayrı değer var olabilir ima f ()iki değer olsaydı: x, y :: f ()o zaman, x == husk ()ve husk () == ybu yüzden, x == y. Ancak sadece bir olası f ()değer varsa, fsabit şekle sahip olmalıdır. (örn için data Pair a = Pair a atürden yalnızca bir değeri vardır, Pair ()bu varlık Pair () (), ancak tip birden fazla değer vardırMaybe () veya[()] .)husk . unhusk == idfsabit şekle sahip olması gerektiği anlamına gelir .


Hm. Fantezi GADT'lerin ve eşyaların varlığında " yalnızca tek bir tipte değer olabilir" ifadesinin "değişemeyeceği f ()oluşumların sayısını" ima ettiği gerçekten açık mı a?
Daniel Wagner

@DanielWagner “Örnekleme olaylarının sayısı değişemez” abir StrongApplicativeörnek için yeterli bir koşul değildir ; örneğin, data Writer w a = Writer (w,a)değişken olmayan bir çokluğa sahiptir a, ancak bir değildir StrongApplicative. Aslında f ()tekil olmanın bir sonucu olduğuna inandığım, değişmez olmak için işlevcinin şekline ihtiyacınız var .
bradrn

Bunun ne kadar alakalı olduğunu gördüğümden emin değilim. Cevapta, ikinci varsayımı doğrularken, "güçlü uygulama" nın "bir farklı f ()" ima ettiği "değişemeyen olayların sayısını" ima ettiğini iddia ediyorsunuz a. Bu argümanın son adımının açıkça doğru olmadığına itiraz ediyorum; örneğin düşünün data Weird a where One :: a -> Weird a; None :: Weird Bool. Weird ()Farklı bir tip değeri vardır , ancak farklı kurucuların içinde değişen sayıda as vardır. (Burada tam bir karşı örnek değil çünkü Functorzor, ama bunun düzeltilemeyeceğini nasıl biliyoruz?)
Daniel Wagner

@DanielWagner Tek bir nokta olan Weird ()ama sabit şekilli olmayan iyi bir nokta . Ama Weirdbir değil Functor, bu yüzden zaten olamaz StrongApplicative. Alakalı varsayım olurdu herhalde: eğer fbir olduğunu Functormu, f ()bir tekil anlamına olmanın fsabit şekle sahiptir ? Bunun doğru olduğundan şüpheliyim, ancak belirttiğiniz gibi henüz hiçbir kanıtım yok.
bradrn

5

Bu sorulardan en az birini olumsuz olarak cevaplayabiliriz:

Kendi tür argümanındaki öğelerin "sabit boyutlu" bir kabını temsil eden her bir Başvurucu, StrongApplicative'in bir örneğidir

Aslında StrongApplicativeasıl sorudaki yasal olanlardan biri yanlıştır. Yazar başvurucu Monoid => (,) mdeğildir StrongApplicative, çünkü husk $ unhusk $ ("foo", ()) == ("", ()) /= ("foo", ()).

Benzer şekilde, sabit boyutlu bir konteyner örneği:

data Strange a = L a | R a

sabit çokluk 1'in güçlü bir uygulamacı değildir, çünkü eğer husk = Lefto zaman tanımlarız husk $ unhusk $ Right () /= Right ()ve tersi de geçerlidir. Bunu görmenin eşdeğer bir yolu, bunun sadece monoid seçiminiz için başvuran yazar olmasıdır Bool.

Yani olmayan "sabit boyutlu" uygulamalar vardır StrongApplicative. Tüm StrongApplicativeboyutların sabit büyüklükte olup olmadığı hala görülüyor.


5

"Sabit boyutlu konteyner" tanımımız olarak temsil edilebilir functorları ele alalım:

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

Gerçekte Representablebirkaç yasa ve üst sınıf vardır, ancak bu cevabın amaçları için, aslında sadece iki özelliğe ihtiyacımız var:

tabulate . index = id
index . tabulate = id

(Tamam, yasalara da uymalıyız instance StrongApplicative ((->) r). Kolay bezelye, zaten var olduğunu kabul ediyorsun.)

Bu tanımı alırsak, o varsayım 1'i onaylayabilirim:

ApplicativeKendi tür argümanındaki öğelerin "sabit boyutlu" bir kabını temsil eden her biri,StrongApplicative

doğru. Bunu nasıl yapacağınız aşağıda açıklanmıştır:

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

Kanıtlanması gereken çok sayıda yasa var, ancak StrongApplicativeekleyen Big Four'a odaklanacağım - muhtemelen liderlerin zaten olduğuna inanıyorsunuz Applicativeve OpApplicativeeğer bunu yapmazsanız, kanıtları aşağıdaki gibi görünüyor ( bu da birbirine çok benziyor). Anlaşılır olması için, ben kullanacak zipf, huskffonksiyon örneğin, vb, ve zipr, huskrsen hangi hangi takip edebilmek amacıyla, Temsil örneğin vb. (Ve böylece bir varsayım olarak kanıtlamaya çalıştığımız şeyi almadığımızı doğrulamak kolay! unhuskf . huskf = idKanıtlarken kullanmak doğru unhuskr . huskr = id, ancak varsaymak yanlış olurunhuskr . huskr = id aynı kanıtta .)

Her yasanın kanıtı temelde aynı şekilde ilerler: tanımları çöz Representable, sana veren izomorfizmi bırak , sonra işlevler için benzer yasayı kullan.

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)

Şu durulması: instance StrongApplicative f => Representable f where type Rep f = forall x. f x -> x. indexkolay. Hile için tabulatehenüz çalışmadım , ama inanılmaz derecede yakın görünüyor.
Daniel Wagner

@AsadSaeeduddin ile görüştüğümde, aynı StrongApplicativeörneği bulmayı başardım , ancak yasaları kanıtlayamadım. Anladığınız için tebrikler! Ben Representablede verilen örneği yapmaya çalıştım StrongApplicative, ama iyi bir Reptip düşünemiyorum - merak ediyorum, bunu nasıl başarıyorsunuz forall x. f x -> x?
bradrn

@bradrn Bu hipotezin, bu şeylerin hangi elemanların içine yerleştirildiği sabit bir "delik" setine sahip olduğunu hatırlayın. Daha sonra tür işlevleri forall x. f x -> xtam olarak bir delik seçip o delikteki değeri döndüren işlevlerdir. (Ve nasıl uygulanacağını düşünürken tabulate, türüne bir itiraz ettim unhusk; ayrıntılar için sorunun kendisinin yorumlarına bakın.)
Daniel Wagner

Teşekkürler @DanielWagner! Bu gerçekten zekice bir yaklaşım - bunu düşünmezdim.
bradrn

Uygulamayı denedikten sonra, bunun forall x. f x -> xişe yarayacağına ikna olduğumu sanmıyorum Rep. Benim gerekçem, bunu kullanarak Rep, sadece olanlar için değil, herhangi bir tür indexiçin yazabilirsiniz - bu yüzden çok genel olabileceğinden şüpheleniyorum . StrongApplicativeforall x. f x -> x
bradrn
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.