Applicative
类型类表示松散单项函子,该函子将笛卡尔单项结构保留在类型化函数的类别上。
换句话说,给定证明(,)
形成单曲面结构的规范同构:
-- 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
松弛度之间不一定存在良好的关系。因此我们可以使用笛卡尔单曲面结构寻找strong monoidal函子:
class (Applicative f, OpApplicative f) => StrongApplicative f
-- Laws:
-- unhusk . husk = id
-- husk . unhusk = id
-- zip . unzip = id
-- unzip . zip = id
上面的第一定律是微不足道的,因为类型() -> ()
的唯一居民是()
上的恒等函数。
但是,剩下的三个定律,以及子类本身,是[[not琐碎的。具体来说,并非每个Applicative
都是此类的合法实例。
Applicative
函子,可以为它们声明StrongApplicative
的合法实例:Identity
VoidF
(->) r
Monoid m => (,) m
(请参阅答案)Vec (n :: Nat)
Stream
(无限)Applicative
:[]
Either e
Maybe
NonEmptyList
StrongApplicative
类是FixedSize
类,其中“固定大小” *表示a
中居民的多样性** f a
的居民是固定的。
Applicative
代表其类型参数元素的“固定大小”容器都是StrongApplicative
的实例StrongApplicative
的实例,其中a
的出现次数可以变化StrongApplicative
是我最好的尝试。为了评估这是否是一个好的定义,我需要进行一些比较。给定某种形式的/非正式的定义,对于一个函子,对于其类型参数的居民而言,具有给定的大小或多重性是什么意思,问题是StrongApplicative
实例的存在是否能准确地区分固定大小和变化大小的函子。
[由于不了解现有的正式定义,我在使用“固定大小”一词时要求直觉。但是,如果有人已经知道函子大小的现有形式主义并且可以将StrongApplicative
与函子进行比较,那就更好了。
**“多重性”在广义上是指函子的共域类型的居民中出现了多少个函子的参数类型的任意元素。这是
无
VoidF
:固定,0Identity
:固定的1Maybe
:变量,最小0,最大1[]
:变量,最小0,最大无限NonEmptyList
:变量,最小1,最大无限]Stream
:固定的,无限的Monoid m => (,) m
:固定的1data Pair a = Pair a a
:固定,2Either x
:变量,最小0,最大1data Strange a = L a | R a
:固定的1每个表示其类型参数元素的“固定大小”容器的Applicative都是StrongApplicative的一个实例
实际上,原始问题中的合法StrongApplicative
的示例之一是错误的。适用于写作者的Monoid => (,) m
不是StrongApplicative
,因为例如husk $ unhusk $ ("foo", ()) == ("", ()) /= ("foo", ())
。
类似地,固定大小的容器的示例:
data Strange a = L a | R a
固定多重性1,不是很强的适用性,因为如果我们定义husk = Left
,则定义husk $ unhusk $ Right () /= Right ()
,反之亦然。用一种等效的方式可以看出,这只是作者对您选择Bool
上的monoid的适用。因此存在不是
StrongApplicative
的“固定大小”应用程序。是否所有StrongApplicative
的大小都固定,尚待观察。