[英]What kind of morphism is `filter` in category theory?
在范畴理论中, filter
操作是否被视为态射? 如果是,那是什么样的态射? 示例(在Scala中)
val myNums: Seq[Int] = Seq(-1, 3, -4, 2)
myNums.filter(_ > 0)
// Seq[Int] = List(3, 2) // result = subset, same type
myNums.filter(_ > -99)
// Seq[Int] = List(-1, 3, -4, 2) // result = identical than original
myNums.filter(_ > 99)
// Seq[Int] = List() // result = empty, same type
在这个答案中,我将假设您正在讨论Set
filter
(其他数据类型的情况似乎更加混乱)。
让我们先解决我们所说的问题。 我将具体谈谈以下函数(在Scala中):
def filter[A](p: A => Boolean): Set[A] => Set[A] =
s => s filter p
当我们以这种方式写下它时,我们清楚地看到它是一个带有类型参数A
的多态函数,它将谓词A => Boolean
映射到Set[A]
映射到其他Set[A]
函数。 为了使它成为“态射”,我们必须首先找到一些类别,其中这个东西可能是“态射”。 有人可能会希望它的自然转化,因此,在“默认环境类式的结构”中endofunctors类别态射通常被称为“ Hask
”(或“ Scal
‘?’ Scala
”?)。 为了表明它是自然的,我们必须检查下面的图表是否为每个f: B => A
通勤f: B => A
:
- o f
Hom[A, Boolean] ---------------------> Hom[B, Boolean]
| |
| |
| |
| filter[A] | filter[B]
| |
V ??? V
Hom[Set[A], Set[A]] ---------------> Hom[Set[B], Set[B]]
然而,在这里我们立刻失败了,因为它不清楚甚至放在底部的水平箭头上,因为赋值A -> Hom[Set[A], Set[A]]
甚至看起来都不是很有趣(对于同样的原因,为什么A -> End[A]
不是函数,请参见此处和此处 )。
我在这里看到的固定类型A
的唯一“分类”结构如下:
A
可以被认为是部分有序集与含义,也就是p LEQ q
如果p
意味着q
(即,或者p(x)
必须为假,或者q(x)
必须是真实的所有x: A
Set[A] => Set[A]
,我们可以为每个集合定义一个f LEQ g
的偏序s: Set[A]
它认为f(s)
是g(s)
子集。 然后filter[A]
将是单调的,因此是poset类别之间的函子。 但那有点无聊。
当然,对于每个固定的A
,它(或者说它的eta扩展)也只是一个函数,从A => Boolean
到Set[A] => Set[A]
,所以它自动成为“ Hask
”中的“态射” -类别”。 但那更无聊。
查看此事的一个有趣方式是不选择filter
作为原始概念。 有一个名为Filterable
的Haskell类型,它被恰当地描述为 :
像
Functor
一样,但它[包括]Maybe
效果。从形式上看,类
Filterable
代表Kleisli也许到Hask函子。
“ Kleisli Maybe
到Hask的仿函数”的态射映射由类的mapMaybe
方法捕获,这确实是同名Data.Maybe
函数的推广:
mapMaybe :: Filterable f => (a -> Maybe b) -> f a -> f b
阶级法则只是适当的算子法则(请注意Just
和(<=<)
分别是Kleisli中的身份和构成):
mapMaybe Just = id
mapMaybe (g <=< f) = mapMaybe g . mapMaybe f
该课程也可以用catMaybes
来表达......
catMaybes :: Filterable f => f (Maybe a) -> f a
...与mapMaybe
可以相互mapMaybe
(参见sequenceA
和traverse
之间的类似关系)......
catMaybes = mapMaybe id
mapMaybe g = catMaybes . fmap g
......相当于Hask endofunctors之间的自然转换Compose f Maybe
和f
。
所有这些都与你的问题有什么关系? 首先,仿函数是类别之间的态射,自然变换是仿函数之间的态射。 既然如此,就可以在某种意义上谈论这里的态射, 这种态度不像 “ 哈斯克斯的态射”那样乏味 。 你不一定想这样做,但在任何情况下,现有的有利位置。
其次, filter
也是一种Filterable
方法,毫不奇怪,它的默认定义是:
filter :: Filterable f => (a -> Bool) -> f a -> f a
filter p = mapMaybe $ \a -> if p a then Just a else Nothing
或者,使用另一个可爱的组合器拼写它:
filter p = mapMaybe (ensure p)
这间接地使filter
在这个特定的分类概念星座中占有一席之地。
回答是这样的问题,我想首先了解过滤的本质是什么。
例如,输入是一个列表是否重要? 你能过滤一棵树吗? 我不明白为什么不! 您将谓词应用于树的每个节点,并丢弃未通过测试的节点。
但结果的形状是什么? 节点删除并不总是被定义,或者它是不明确的。 你可以返回一个清单。 但为什么要列出? 任何支持追加的数据结构都可行。 您还需要数据结构的空成员来启动附加过程。 所以任何单位岩浆都会这样做。 如果你坚持相关性,你会得到一个幺半群。 回顾filter
的定义,结果是一个列表,这确实是一个幺半群。 所以我们走在正确的轨道上。
因此, filter
只是所谓的Foldable
一种特殊情况:一种数据结构,您可以在将结果累积到一个幺半群时折叠。 特别是,你可以使用谓词来输出单例列表,如果它是真的; 或者一个空列表(标识元素),如果它是假的。
如果你想要一个绝对的答案,那么折叠就是一个变形现象的例子,这是代数范畴中的态射的一个例子。 您正在折叠的(递归)数据结构(列表,在filter
的情况下)是某个仿函数的初始代数(在本例中为列表仿函数),并且您的谓词用于为此仿函数定义代数。
filter
可以用foldRight
写成:
filter p ys = foldRight(nil)( (x, xs) => if (p(x)) x::xs else xs ) ys
foldRight
on lists是T-algebras的映射(这里T是List数据类型foldRight
函数),因此filter
是T-algebras的映射。
这里讨论的两个代数是初始列表代数
[nil, cons]: 1 + A x List(A) ----> List(A)
而且,让我们说“过滤器”代数,
[nil, f]: 1 + A x List(A) ----> List(A)
其中f(x, xs) = if p(x) x::xs else xs
。
在这种情况下filter(p, _)
让我们将filter(p, _)
称为从初始代数到过滤器代数的唯一映射(在一般情况下称为fold
)。 它是代数映射的事实意味着满足以下等式:
filter(p, nil) = nil
filter(p, x::xs) = f(x, filter(p, xs))
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.