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