Applicative
Typeclass 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; OpApplicative
aş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 Applicative
işlev (gerçekten, herhangi bir Functor
) önemsiz OpApplicative
olsa da, Applicative
gevşeklik ve OpApplicative
oplaksite 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 Applicative
biri bu sınıfın yasal bir örneği değildir .
İşte Applicative
yasal örneklerini beyan edebileceğimiz bazı işlevler StrongApplicative
:
Identity
VoidF
(->) r
(cevaplara bakınız)Monoid m => (,) m
Vec (n :: Nat)
Stream
(sonsuz)
Ve işte Applicative
yapamayacağımız bazı s:
[]
Either e
Maybe
NonEmptyList
Buradaki desen, StrongApplicative
sınıfın bir anlamda FixedSize
sınıf olduğunu gösterir, burada "sabit boyut" * , bir sakinte yaşayanların çokluğunun ** sabit olduğu anlamına gelir .a
f a
Bu iki varsayım olarak ifade edilebilir:
Applicative
Kendi tür argümanındaki öğelerin "sabit boyutlu" bir kabını temsil eden her biri,StrongApplicative
StrongApplicative
Oluşma sayısınına
değ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 StrongApplicative
onunla 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, 0Identity
: sabit, 1Maybe
: değişken, minimum 0, maksimum 1[]
: değişken, minimum 0, maksimum sonsuzNonEmptyList
: değişken, minimum 1, maksimum sonsuzStream
: sabit, sonsuzMonoid m => (,) m
: sabit, 1data Pair a = Pair a a
: sabit, 2Either x
: değişken, minimum 0, maksimum 1data Strange a = L a | R a
: sabit, 1
(->) r
bunlar doğru şekilde izomorfiktir.
(->) r
; güçlü uygulama yapısını korumak için izomorfizmin bileşenlerine ihtiyacınız vardır. Herhangi bir nedenle Representable
Haskell'deki tip sınıfının gizemli bir tabulate . return = return
yasası 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 tabulate
ve zip
uygun bir monoid kategorisinin morfizmleri. . Diğer üçü ise talep etmeniz gereken ekstra yasalardır.
tabulate
ve index
uygun bir kategorinin morfizmleri ..." olmalıdır
return
ciddi bir sorun değildir. cotraverse getConst . Const
, return
/ pure
açısından varsayılan bir uygulamadır Distributive
ve dağıtımcılar / temsil edilebilirler sabit bir şekle sahip olduğundan, bu uygulama benzersizdir.