Haskell 中的附加用例

Use cases for adjunctions in Haskell

我一直在阅读 adjunctions during the last couple of days. While I start to understand their importance from a theoretical point of view, I wonder how and why people use them in Haskell. Data.Functor.Adjunction provides an implementation and among its instances are free functor / forgetful functor and curry / uncurry。同样,从理论的角度来看,这些非常有趣,但我看不出如何将它们用于更实际的编程问题。

是否有人们使用 Data.Functor.Adjunction 解决编程问题的示例?为什么您更喜欢此实现而不是其他实现?

初步说明:这个答案有点推测性。就像问题一样,它是通过研究 Data.Functor.Adjunction.

构建的

我能想到 Adjunction class 在野外没有太多用例的三个原因。

首先,所有 Hask/Hask 附加词最终都是柯里化附加词的一些变体,因此潜在实例的范围并不是一开始就那么大。许多可能感兴趣的附属词不是 Hask/Hask。

其次,虽然 Adjunction 实例可以免费为您提供大量其他实例,但在许多情况下,这些实例已经存在于其他地方。要选择 ur-example,我们可以很容易地根据 Control.Monad.Trans.Adjoint:

来实现 StateT
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。也就是说,如果您确实有自己的 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 实例会免费为我们提供 Dilemma (ChoiceF a) 的 monad 转换器。

(另一种可能性可能是利用 the Free f/Cofree u adjunctionCofree Dilemma a 是一个无限的结果树,而 Free ChoiceF a 是通往结果的路径。我敢说有一些里程离开那个。)

第三,虽然 Data.Functor.Adjunction 中的右伴随函数有很多有用的函数,但它们提供的大部分函数也可以通过 Representable and/or Distributive 获得,所以大多数可能使用它们的地方最终都坚持使用 superclasses。

Data.Functor.Adjunction当然也为left伴随提供有用的函数。一方面,左伴随(与对同构,即包含单个元素的容器)可能不如右伴随(与函数同构,即具有单一形状的函子)通用;另一方面,左伴随似乎没有任何规范的 class(至少现在还没有),因此这可能会导致实际使用 Data.Functor.Adjunction 函数的机会。顺便说一句,Chris Penner's battleship example 您建议的可以说符合要求,因为它确实依赖于左伴随以及如何使用它来编码右伴随的表示:

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 可以(从字面上看,在这种情况下),在使用有效载荷的同时定位位置。