[英]To what extent are Applicative/Monad instances uniquely determined?
As described this question/answers , Functor
instances are uniquely determined, if they exists. 如本问题所述,
Functor
实例是唯一确定的(如果存在)。
For lists, there are two well know Applicative instances: []
and ZipList
. 对于列表,有两个众所周知的Applicative实例:
[]
和ZipList
。 So Applicative isn't unique (see also Can GHC derive Functor and Applicative instances for a monad transformer? and Why is there no -XDeriveApplicative
extension? ). 因此, Applicative不是唯一的 (另请参见GHC可以为monad转换器派生Functor和Applicative实例吗? 为什么没有
-XDeriveApplicative
扩展? )。 However, ZipList
needs infinite lists, as its pure
repeats a given element indefinitely. 但是,
ZipList
需要无限列表,因为其pure
无限期地重复给定元素。
Applicative
instances? Applicative
实例的数据结构示例,也许是更好的示例? Going further, if we could extend both []
and ZipList
to a Monad, we'd have an example where a monad isn't uniquely determined by the data type and its Functor. 更进一步,如果我们可以将
[]
和ZipList
都扩展为Monad,我们将有一个示例,其中monad不是由数据类型及其Functor唯一地确定的。 Alas, ZipList
has a Monad instance only if we restrict ourselves to infinite lists ( streams ). ZipList
只有当我们将自己限制在无限列表 ( 流 )中时, ZipList
才具有Monad实例。 And return
for []
creates a single-element list, so it requires finite lists. return
[]
会创建一个单元素列表,因此它需要有限列表。 Therefore: 因此:
In the case there is an example with two or more distinct instances, an obvious question arises, if they must/can have the same Applicative instance: 在有两个或多个不同实例的示例的情况下,如果它们必须/可以具有相同的Applicative实例,就会出现一个明显的问题:
And finally we can ask the same question for Alternative/MonadPlus. 最后,我们可以对Alternative / MonadPlus提出相同的问题。 This is complicated by the fact that there are two distinct set of MonadPlus laws .
由于存在两种不同的MonadPlus法则 ,这使情况变得复杂。 Assuming we accept one of the set of laws (and for Applicative we accept right/left distributivity/absorption , see also this question ),
假设我们接受其中一组定律(对于应用,我们接受右/左分布/吸收 ,另请参见此问题 ),
If any of the above are unique, I'd be interested in knowing why, to have a hint of a proof. 如果以上任何一个都不是唯一的,我很想知道为什么,以得到一个提示。 If not, an counter-example.
如果不是,则为反例。
First, since Monoid
s are not unique, neither are Writer
Monad
s or Applicative
s. 首先,由于
Monoid
不是唯一的,所以Writer
Monad
或Applicative
都不一样。 Consider 考虑
data M a = M Int a
then you can give it Applicative
and Monad
instances isomorphic to either of: 那么您可以将
Applicative
和Monad
实例同构为以下任意一个:
Writer (Sum Int)
Writer (Product Int)
Given a Monoid
instance for a type s
, another isomorphic pair with different Applicative
/ Monad
instances is: 给定类型
s
的Monoid
实例,另一个具有不同Applicative
/ Monad
实例的同构对是:
ReaderT s (Writer s)
State s
As for having one Applicative
instance extend to two different Monad
s, I cannot remember any example. 至于将一个
Applicative
实例扩展到两个不同的Monad
,我不记得任何示例。 However, back when I tried to convince myself completely about whether ZipList
really cannot be made a Monad
, I found the following pretty strong restriction that holds for any Monad
: 但是,当我试图完全说服
ZipList
是否真的不能成为Monad
,我发现以下对Monad
严格限制:
join (fmap (\x -> fmap (\y -> f x y) ys) xs) = f <$> xs <*> ys
That doesn't give join
for all values though: in the case of lists the restricted values are the ones where all elements have the same length, ie lists of lists with "rectangular" shape. 但是,这并不能为所有值提供
join
:对于列表,限制值是所有元素都具有相同长度的值,即具有“矩形”形状的列表的列表。
(For Reader
monads, where the "shape" of monadic values doesn't vary, these are in fact all the m (mx)
values, so those do have unique extension. EDIT: Come to think of it, Either
, Maybe
and Writer
also have only "rectangular" m (mx)
values, so their extension from Applicative
to Monad
is also unique.) (对于
Reader
monad,其monadic值的“形状”没有变化,实际上它们都是m (mx)
值,因此它们确实具有唯一的扩展名。编辑:来思考一下, Either
, Maybe
和Writer
也只有“矩形” m (mx)
值,因此它们从Applicative
到Monad
的扩展名也是唯一的。)
I wouldn't be surprised if an Applicative
with two Monad
s exists, though. 但是,如果存在带有两个
Monad
的Applicative
,我不会感到惊讶。
For Alternative
/ MonadPlus
, I cannot recall any law for instances using the Left Distribution law instead of Left Catch, I see nothing preventing you from just swapping (<|>)
with flip (<|>)
. 对于
Alternative
/ MonadPlus
,对于使用“左分布”定律而不是“左捕获” 定律的实例, 我无法回忆起任何定律 ,我看不出有什么可以阻止您仅将(<|>)
与flip (<|>)
交换。 I don't know if there's a less trivial variation. 我不知道是否有比较小的变化。
ADDENDUM: I suddenly remembered I had found an example of an Applicative
with two Monad
s. 附录:我突然想起我找到了一个示例
Applicative
有两个Monad
秒。 Namely, finite lists. 即,有限列表。 There's the usual
Monad []
instance, but you can then replace its join
by the following function (essentially making empty lists "infectious"): 这是通常的
Monad []
实例,但是您可以用以下函数替换其join
(基本上使空列表具有“感染性”):
ljoin xs
| any null xs = []
| otherwise = concat xs
(Alas, the lists need to be finite because otherwise the null
check will never finish, and that would ruin the join . fmap return == id
monad law.) (A,列表必须是有限的,因为否则
null
检查将永远不会完成,并且会破坏join . fmap return == id
monad law。)
This has the same value as join
/ concat
on rectangular lists of lists, so will give the same Applicative
. 它与矩形列表中的
join
/ concat
具有相同的值,因此具有相同的Applicative
。 As I recall, it turns out that the first two monad laws are automatic from that, and you just need to check ljoin . ljoin == ljoin . fmap ljoin
我记得,事实证明,前两个monad定律是自动产生的,您只需要检查
ljoin . ljoin == ljoin . fmap ljoin
ljoin . ljoin == ljoin . fmap ljoin
ljoin . ljoin == ljoin . fmap ljoin
. ljoin . ljoin == ljoin . fmap ljoin
。
Given that every Applicative
has a Backwards
counterpart, 鉴于每个
Applicative
都有一个Backwards
对应项,
newtype Backwards f x = Backwards {backwards :: f x}
instance Applicative f => Applicative (Backwards f) where
pure x = Backwards (pure x)
Backwards ff <*> Backwards fs = Backwards (flip ($) <$> fs <*> ff)
it's unusual for Applicative
to be uniquely determined, just as (and this is very far from unrelated) many sets extend to monoids in multiple ways. 对
Applicative
唯一地确定是不寻常的,就像许多集合以多种方式扩展到类半体一样(这是很不相关的)。
In this answer , I set the exercise of finding at least four distinct valid Applicative
instances for nonempty lists: I won't spoil it here, but I will give a big hint on how to hunt. 在此答案中 ,我将练习为非空列表至少查找四个不同的有效
Applicative
实例:我不会在这里宠坏它,但会为如何狩猎提供很大的提示。
Meanwhile, in some wonderful recent work (which I saw at a summer school a few months ago), Tarmo Uustalu showed a rather neat way to get a handle on this problem, at least when the underlying functor is a container , in the sense of Abbott, Altenkirch and Ghani. 同时,在最近的一些出色的工作中(我几个月前在一家暑期学校看到的),Tarmo Uustalu展示了一种解决此问题的巧妙方法,至少在底层函子是容器的情况下 ,雅培,阿尔滕基希和加尼。
Warning: Dependent types ahead! 警告:前面的依赖类型!
What is a container? 什么是容器? If you have dependent types to hand, you can present container-like functors F uniformly, as being determined by two components
如果您要处理依赖类型,则可以由两个组件确定,均匀地呈现类似容器的函子F
Up to isomorphism, container data structures in FX are given by the dependent pair of some shape s : S, and some function e : P s -> X, which tells you the element located at each position. 直到同构为止,FX中的容器数据结构由某些形状s:S和一些函数e:P s-> X的相关对提供,这些告诉您位于每个位置的元素。 That is, we define the extension of a container
也就是说,我们定义了容器的扩展名
(S <| P) X = (s : S) * (P s -> X)
(which, by the way, looks a lot like a generalized power series if you read ->
as reversed exponentiation). (顺便说一句,如果您将
->
读为反幂,它看起来很像广义幂级数)。 The triangle is supposed to remind you of a tree node sideways, with an element s : S labelling the apex, and the baseline representing the position set P s. 三角形应该让您想起树形节点的侧面,元素s:S标记顶点,基线表示位置集P s。 We say that some functor is a container if it is isomorphic to some
S <| P
我们说某些函子是容器,如果它与某些
S <| P
同构S <| P
S <| P
. S <| P
。
In Haskell, you can easily take S = F ()
, but constructing P
can take quite a bit of type-hackery. 在Haskell中,您可以轻松地采用
S = F ()
,但是构造P
可能会占用很多类型黑客。 But that is something you can try at home. 但这是您可以在家尝试的方法。 You'll find that containers are closed under all the usual polynomial type-forming operations, as well as identity,
您会发现容器在所有常见的多项式类型形成操作以及标识,
Id ~= () <| \ _ -> ()
composition, where a whole shape is made from just one outer shape and an inner shape for each outer position, 构图,其中整个形状仅由一个外部形状和每个外部位置的内部形状组成,
(S0 <| P0) . (S1 <| P1) ~= ((S0 <| P0) S1) <| \ (s0, e0) -> (p0 : P0, P1 (e0 p0))
and some other things, notably the tensor , where there is one outer and one inner shape (so "outer" and "inner" are interchangeable) 还有其他一些东西,特别是张量 ,那里有一个外部形状和一个内部形状(因此“外部”和“内部”可以互换)
(S0 <| P0) (X) (S1 <| P1) = ((S0, S1) <| \ (s0, s1) -> (P0 s0, P1 s1))
so that F (X) G
means " F
-structures of G
-structures-all-the-same-shape", eg, [] (X) []
means rectangular lists-of-lists. 因此,
F (X) G
表示“ G
结构的F
结构-相同形状”,例如[] (X) []
表示矩形列表。 But I digress 但是我离题
Polymorphic functions between containers Every polymorphic function 容器之间的多态函数每个多态函数
m : forall X. (S0 <| P0) X -> (S1 <| P1) X
can be implemented by a container morphism , constructed from two components in a very particular way. 可以通过容器形态来实现, 容器形态由两个组件以非常特殊的方式构造。
f : S0 -> S1
mapping input shapes to output shapes; f : S0 -> S1
将输入形状映射到输出形状; g : (s0 : S0) -> P1 (f s0) -> P0 s0
mapping output positions to input positions. g : (s0 : S0) -> P1 (f s0) -> P0 s0
将输出位置映射到输入位置。 Our polymorphic function is then 那么我们的多态函数是
\ (s0, e0) -> (f s0, e0 . g s0)
where the output shape is computed from the input shape, then the output positions are filled up by picking elements from input positions. 其中从输入形状计算出输出形状,然后通过从输入位置拾取元素来填充输出位置。
(If you're Peter Hancock, you have a whole other metaphor for what's going on. Shapes are Commands; Positions are Responses; a container morphism is a device driver , translating commands one way, then responses the other.) (如果您是Peter Hancock,那么您对正在发生的事情有一个完全的比喻。形状是命令;位置是响应;容器形态是设备驱动程序 ,一种方式翻译命令,然后另一种方式响应。)
Every container morphism gives you a polymorphic function, but the reverse is also true. 每个容器的态素都为您提供了一个多态函数,但反之亦然。 Given such an m, we may take
给定这样一个m,我们可能会
(f s, g s) = m (s, id)
That is, we have a representation theorem , saying that every polymorphic function between two containers is given by such an f
, g
-pair. 也就是说,我们有一个表示定理 ,说两个容器之间的每个多态函数都由这样一个
f
, g
对给出。
What about Applicative
? 那么
Applicative
呢? We kind of got a bit lost along the way, building all this machinery. 在构建所有这些机器的过程中,我们有点迷路了。 But it has been worth it.
但它是值得的。 When the underlying functors for monads and applicatives are containers, the polymorphic functions
pure
and <*>
, return
and join
must be representable by the relevant notion of container morphism. 当monads和appadatives的基础函子为容器时,多态函数
pure
和<*>
, return
和join
必须由容器态射的相关概念表示。
Let's take applicatives first, using their monoidal presentation. 首先,让我们使用应用程序的半形形式。 We need
我们需要
unit : () -> (S <| P) ()
mult : forall X, Y. ((S <| P) X, (S <| P) Y) -> (S <| P) (X, Y)
The left-to-right maps for shapes require us to deliver 形状的从左到右的地图要求我们提供
unitS : () -> S
multS : (S, S) -> S
so it looks like we might need a monoid. 所以看起来我们可能需要一个半身像。 And when you check that the applicative laws, you find we need exactly a monoid.
当您检查适用法律时,您会发现我们恰恰需要一个半同等式。 Equipping a container with applicative structure is exactly refining the monoid structures on its shapes with suitable position-respecting operations.
为容器配备可应用的结构是通过适当的位置尊重操作来精确地将单面体结构细化为其形状。 There's nothing to do for
unit
(because there is no chocie of source position), but for mult
, we need that whenenver unit
无关(因为没有源位置的选择),但是对于mult
,我们需要在
multS (s0, s1) = s
we have 我们有
multP (s0, s1) : P s -> (P s0, P s1)
satisfying appropriate identity and associativity conditions. 满足适当的身份和关联性条件。 If we switch to Hancock's interpretation, we're defining a monoid (skip, semicolon) for commands, where there is no way to look at the response to the first command before choosing the second, like commands are a deck of punch cards.
如果切换到汉考克的解释,我们将为命令定义一个等分线(跳过,分号),在选择第二个命令之前,无法查看对第一个命令的响应,就像命令是一副打孔卡一样。 We have to be able to chop up responses to combined commands into the individual responses to the individual commands.
我们必须能够将对组合命令的响应分成对单个命令的单个响应。
So, every monoid on the shapes gives us a potential applicative structure. 因此,形状上的每个monoid都为我们提供了潜在的应用结构。 For lists, shapes are numbers (lengths), and there are a great many monoids from which to choose.
对于列表,形状是数字(长度),并且有很多可供选择的monoid。 Even if shapes live in
Bool
, we have quite a bit of choice. 即使形状存在于
Bool
,我们也有很多选择。
What about Monad
? 那
Monad
呢? Meanwhile, for monads M
with M ~= S <| P
同时,对于M〜
M ~= S <| P
单子M
M ~= S <| P
. M ~= S <| P
。 We need 我们需要
return : Id -> M
join : M . M -> M
Looking at shapes first, that means we need a sort-of lopsided monoid. 首先看形状,这意味着我们需要一种偏斜的类半体。
return_f : () -> S
join_f : (S <| P) S -> S -- (s : S, P s -> S) -> S
It's lopsided because we get a bunch of shapes on the right, not just one. 这是不平衡的,因为我们在右侧获得了很多形状,而不仅仅是一个。 If we switch to Hancock's interpretation, we're defining a kind of sequential composition for commands, where we do let the second command be chosen on the basis of the first response, like we're interacting at a teletype.
如果切换到汉考克的解释,我们将为命令定义一种顺序组成,在这种情况下,我们会根据第一个响应选择第二个命令,就像在电传打字机上进行交互一样。 More geometrically, we're explaining how to glom two layers of a tree into one.
从几何角度上讲,我们正在解释如何将树的两层粘合为一层。 It would be very surprising if such compositions were unique.
如果这种组合物是独特的,那将是非常令人惊讶的。
Again, for the positions, we have to map single output positions to pairs in a coherent way. 同样,对于位置,我们必须以连贯的方式将单个输出位置映射为对。 This is trickier for monads: we first choose an outer position (response), then we have to choose an inner position(response) appropriate to the shape (command) found at the first position (chosen after the first response).
这对于单子来说比较棘手:我们首先选择一个外部位置(响应),然后我们必须选择一个适合于在第一个位置(在第一个响应之后选择)的形状(命令)的内部位置(响应)。
I'd love to link to Tarmo's work for the details, but it doesn't seem to have hit the streets yet. 我很想链接到Tarmo的工作中,以获取详细信息,但似乎还没有出现。 He has actually used this analysis to enumerate all possible monad structures for several choices of underlying container.
他实际上已经使用此分析来枚举用于基础容器的几种选择的所有可能的monad结构。 I'm looking forward to the paper!
我期待着这篇论文!
Edit. 编辑。 By way of doing honour to the other answer, I should observe that when everywhere
P s = ()
, then (S <| P) X ~= (S, X)
and the monad/applicative structures coincide exactly with each other and with the monoid structures on S
. 通过尊重其他答案,我应该观察到,当无处不在
P s = ()
,则(S <| P) X ~= (S, X)
与monad /应用结构彼此完全一致,并且与S
上的monoid结构。 That is, for writer monads, we need only choose the shape-level operations, because there is exactly one position for a value in every case. 也就是说,对于编写器monad,我们只需要选择形状级别的操作,因为在每种情况下,值的位置恰好只有一个位置。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.