【问题标题】:What is the name of this functor-ish tag-like typeclass?这个类似仿函数标签的类型类的名称是什么?
【发布时间】:2016-05-04 22:19:59
【问题描述】:

我注意到我有很多函数可以为我的值添加某种标签。例如,考虑以下两种数据类型:

data Named a = Named String a                                                   
data Colored a = White a | Black a

以及一些使用它们的函数:

name :: Foo -> Named Foo
color :: Named Foo -> Colored (Named Foo)

在某个时候,我开始使用带有许多嵌套“标签”的函数,所以我想知道是否可以将其概括为更易于管理。所有这些都可能很好地与 PureScript 的行多态性一起工作,但我们在这里谈论的是 Haskell。无论如何,这是我想出的:

class Tag f where                                                  
    separate :: f a -> (forall b. b -> f b, a)

法律大概是这样的:

fx = let (f, x) = separate fx in f x

或不进行类型检查但更优雅的版本:

uncurry ($) . separate = id

Tag 也可以成为Functor 的子类,前提是

fmap g fx = let (f, x) = separate fx in f (g x)

示例数据类型的实例如下:

instance Tag Named where
    separate (Named name x) = (Named name, x)

instance Tag Colored where
    separate (White x) = (White, x)
    separate (Black x) = (Black, x)

...以及其他一些一般情况:

instance Tag Identity where
    separate (Identity x) = (Identity, x)

instance (Tag f, Tag g) => Tag (Compose f g) where
    separate (Compose fgx) =
        let (f, gx) = separate fgx in
        let (g, x) = separate gx in
        (Compose . f . g, x)

使整个类型类真正有用的是这个函数:

reorder :: (Tag f, Tag g) => f (g a) -> g (f a)
reorder fgx =
    let (f, gx) = separate fgx in
    let (g, x) = separate gx in
    g (f x)

它看起来像是一些显而易见的习语,因此社区必须已经知道它。当您不知道您正在搜索的事物的名称并且 Hoogle 没有任何结果的回应时,Google 并不是很有帮助。

所以我在这里,寻找一个名字,甚至一些图书馆,看看我还能用那个东西做什么。

【问题讨论】:

  • 这看起来可能与 DistributiveRepresentable 类有某种联系。
  • 函数的类型和你给它的规律非常强大——一个Tag f可能只包含一个a类型的值。 reorder 在这里真的没有做任何事情 - Tag 的所有实例都与 (X, a) 同构,对于某些 X,所以它的类型几乎是 (x, (y, a)) -> (y, (x, a))
  • @user2407038:现在你已经说过它看起来很明显。我想我只是太努力了......

标签: haskell typeclass functor


【解决方案1】:

user2407038's comment 确实触及了它的核心,因为您最终要表达的概念归结为与某些对函子同构的函子——毕竟,对是一个附加了其他东西的值。从这个有利的角度来看,还有一些可能有趣的额外事情需要注意。

为方便起见,我假设您的Tags 是Functors(您提到的相关条件通过参数化成立),并通过将forall b. b -> f b 替换为同构f () 来简化类型。那么我们可能有:

separate :: Tag f => f a -> (f (), a)

法律规定:

slot . separate = id

左逆在哪里:

slot :: Functor f => (f (), a) -> f a
slot (sh, a) = fmap (const a) sh

通过添加slot 应该是满射的要求(就您的用例而言,这是完全合理的),slot 升级为完全逆,从而为我们提供了f a 和 @ 之间的同构987654337@.

这些功能至少存在于生态系统的一处:the adjunctions package:

splitL :: Adjunction f u => f a -> (a, f ())
unsplitL :: Functor f => a -> f () -> f a

Hask/Hask 左伴随与配对函子同构,Hask/Hask 右伴随与Representable 是同构的,即与函数函子同构。 dfeuer's suspicion 在某种程度上是合理的,尽管 adjunctions 并没有给我们留下 DistributiveRepresentable 的对应物。以下是他们的草图,并附有编造的名字:

class Traversable t => Lone t where
    codistribute :: Functor f => t (f a) -> f (t a)
    surround :: Functor f => (a -> f b) -> t a -> f (t b)

class Lone f => Detachable f where
    type Corep f
    cotabulate :: (Corep f, a) -> f a
    coindex :: f a -> (Corep f, a)

关于Traversable连接的几点说明:

  • codistributesurround 分别只是 sequenceAtraverse,除了将 Applicative 约束放松到 Functor (如果总是只有一个值,Applicative 是不必要)。

  • 同理,cotabulatecoindex(或slotseparate,或unsplitLsplitL)可以看作是the shape-and-contents decomposition of traversable functors(其中我们不需要内容的列表/向量,因为总是只有一个值)。

  • 可以想象通过Detachable 翻译对的各种实例。对于Comonad,甚至不需要,因为Lone 就足够了(另请参阅adjunctions 中的extractL and duplicateL)。

  • surround 是 van Laarhoven 镜头(Lens (t a) (t b) a b,用 镜头 的说法),就像 traverse 是 van Laarhoven 遍历 (Traversal (t a) (t b) a b)。

最后但同样重要的是,codistribute 是您的reorder 的概括。

【讨论】:

    猜你喜欢
    • 2010-10-27
    • 2016-08-16
    • 2017-06-28
    • 2020-01-29
    • 1970-01-01
    • 1970-01-01
    • 2021-01-13
    • 1970-01-01
    • 2019-05-20
    相关资源
    最近更新 更多