初步说明:这个答案有点推测性。就像这个问题一样,它是通过研究而建立的Data.Functor.Adjunction
.
我可以想到为什么没有太多用例的三个原因Adjunction
在野外上课。
首先,所有 Hask/Hask 附加项最终都是柯里化附加项的某种变体,因此潜在实例的范围一开始并不是那么大。人们可能感兴趣的许多附加功能并不是 Hask/Hask。
其次,虽然Adjunction
坦率地说,实例免费为您提供了大量其他实例,在许多情况下,这些实例已经存在于其他地方。要选择 ur-example,我们可以很容易地实现StateT
按照Control.Monad.Trans.Adjoint http://hackage.haskell.org/package/adjunctions-4.4/docs/Control-Monad-Trans-Adjoint.html:
newtype StateT s m a = StateT { runStateT :: s -> m (s, a) }
deriving (Functor, Applicative, Monad) via AdjointT ((,) s) ((->) s) m
deriving MonadTrans via AdjointT ((,) s) ((->) s)
-- There is also a straightforward, fairly general way to implement MonadState.
然而,没有人需要真正这样做,因为有一个非常好的方法StateT
in 变形金刚。也就是说,如果您确实有Adjunction
你自己的例子,你可能很幸运。我想到的一件可能有意义的小事(即使我还没有真正看到它)是以下函子:
data Dilemma a = Dilemma { fstDil :: a, sndDil a }
data ChoiceF a = Fst a | Snd a
我们可能会写一个Adjunction ChoiceF Dilemma
实例,反映了如何Dilemma (ChoiceF a)
是物化版本State Bool a
. Dilemma (ChoiceF a)
可以被认为是决策树中的一个步骤:选择决策树的一侧Dilemma
告诉你,通过ChoiceF
构造者,接下来要做出什么选择。这Adjunction
然后实例会给我们一个 monad 转换器Dilemma (ChoiceF a)
免费。
(另一种可能性可能是利用the Free f/Cofree u附加 https://hackage.haskell.org/package/adjunctions-4.4/docs/Data-Functor-Adjunction.html#t:Adjunction. Cofree Dilemma a
是一个无限的结果树,而Free ChoiceF a
是一条通往结果的道路。我敢说还有一些里程可以摆脱这种情况。)
第三,虽然右伴随有许多有用的函数Data.Functor.Adjunction
,它们提供的大部分功能也可以通过Representable
and/or Distributive
,因此大多数可能使用它们的地方最终都会坚持使用超类。
Data.Functor.Adjunction
当然,还提供了有用的功能left伴随物。一方面,左伴随(与对同构,即包含单个元素的容器)可能不如右伴随(与函数同构,即具有单一形状的函子)通用;另一方面,似乎没有任何左伴随的规范类(至少还没有),因此这可能会导致实际使用的机会Data.Functor.Adjunction
功能。顺便,克里斯·彭纳的战舰示例 https://chrispenner.ca/posts/adjunction-battleship您的建议可以说符合要求,因为它确实依赖于左伴随以及如何使用它来编码右伴随的表示:
zapWithAdjunction :: Adjunction f u => (a -> b -> c) -> u a -> f b -> c
zapWithAdjunction @CoordF @Board :: (a -> b -> c) -> Board a -> CoordF b -> c
checkHit :: Vessel -> Weapon -> Bool
shoot :: Board Vessel -> CoordF Weapon -> Bool
CoordF
,左伴随,携带板的坐标和有效负载。zapWithAdjunction
使得在使用有效载荷时能够(从字面上看,在这种情况下)定位位置。