【发布时间】: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 并不是很有帮助。
所以我在这里,寻找一个名字,甚至一些图书馆,看看我还能用那个东西做什么。
【问题讨论】:
-
这看起来可能与
Distributive和Representable类有某种联系。 -
函数的类型和你给它的规律非常强大——一个
Tag f可能只包含一个a类型的值。reorder在这里真的没有做任何事情 -Tag的所有实例都与(X, a)同构,对于某些X,所以它的类型几乎是(x, (y, a)) -> (y, (x, a))。 -
@user2407038:现在你已经说过它看起来很明显。我想我只是太努力了......