我一直在阅读adjunctions在过去的几天里。当我开始从理论角度理解它们的重要性时,我想知道人们如何以及为什么在 Haskell 中使用它们。 Data.Functor.Adjunction
提供了一个实现,其实例有 free functor / forgetful仿函数和curry / uncurry 。同样,从理论角度来看,这些非常有趣,但我不知道如何将它们用于更实际的编程问题。
是否有人们使用 Data.Functor.Adjunction
解决编程问题的示例以及为什么您更喜欢此实现而不是其他实现?
最佳答案
初步说明:这个答案有点推测性。就像这个问题一样,它是通过研究 Data.Functor.Adjunction 构建的。
我可以想到为什么 Adjunction
类在野外没有太多用例的三个原因。
首先,所有 Hask/Hask 附加项最终都是柯里化(Currying)附加项的某种变体,因此潜在实例的范围一开始并不是那么大。人们可能感兴趣的许多辅助不是 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
实例,它反射(reflect)了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
和/或 Distributive
,因此大多数可能使用它们的地方最终都会坚持使用父类(super class)。
Data.Functor.Adjunction
当然,还为左伴随词提供有用的函数。一方面,左伴随(与对同构,即包含单个元素的容器)可能不如右伴随(与函数同构,即具有单一形状的仿函数)通用;另一方面,似乎没有任何左伴随的规范类(至少现在还没有),因此这可能会带来实际使用 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
可以(在本例中字面意思是)在使用有效负载时定位目标位置。
关于haskell - Haskell 中附加词的用例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56559213/