地图函数(Seq.map,List.map等)是否具有隐含的后置条件,即输出与输入具有相同数量的项目?更进一步,如果我们有某种Tree.map函数,是否假设输入和输出树的“形状”是相同的?
我问的原因是我总是做出这样的假设(我怀疑很多代码映射的代码也是如此),但后来我发现如果映射,Set.map可以返回一个较小的集合函数产生重复。因此,我的假设无效,或者Set不应被视为用于映射目的的序列。这是什么?
答案 0 :(得分:4)
很多观点,这是我的:
我们可以将所有map
函数/方法视为Haskell的fmap
Functors的特定情况。从该定义我们可以假设结构将被保留(加上一些其他有趣的属性)。
但是在.NET中没有类型类,所以我们可以定义map
来限制Functors'结果是一些Functor属性不会被保留,但是因为有没有影响影响的通用代码是有限的。
所以没有什么能阻止我们定义map
:
请注意,在某些情况下,在类型和值级别都存在限制,例如对于集合,类型级别的限制是两种类型' a和&b; b应该具有比较而对函数的限制值是函数应该是injective。
如果语言能够表达类型级别约束,则编译器将在不满足这些要求时抛出错误。
对于函数值,没有编译时限制,但如果我们想确保它们是正确的,我们可以创建单元测试。但是如果我们不关心限制这些功能会发生什么呢?
好吧,只要我们了解某些Functor属性将不会被遵守,那么使用地图而不是限制Functor就没有错。
因此,我们可以在排序列表中定义map
结构,当然我们不能假设在这些情况下map a >> map b
总是等同于map (a >> b)
。这里的限制是函数应该是monotonically increasing。
注意:对于Haskell,有一个package带有限制仿函数和一个集合实例
答案 1 :(得分:3)
是的,我希望map
函数能够尊重输入的结构(尽管许多实现可能没有明确的测试)。
在Set.map
的情况下,可以认为给定(参数)map
本身的实现是正确的,但参数函数必须是injective 整体映射函数是结构保留的。实际上,对于集合来说,它是两个函数的组合属性。
使用一些验证来包装Set.map
很容易,这些验证在应用时测试参数函数的注入性。
答案 2 :(得分:3)
集合有点棘手,因为您只能创建一组可以测试它们是否相等的东西。实际上,F#集实际上表示为树,因此您需要能够比较它们。
这也意味着集合的map
函数与列表的map
函数不同:
List.map : ('a -> 'b) -> 'a list -> 'b list
Set.map : ('a -> 'b) -> Set<'a> -> Set<'b>) when 'a : comparison and 'b : comparison
您必须能够比较 'b
值的事实解释了为什么集合上的map
函数可以比常规map
函数做更多的事情列表和序列。所以,它不是普通的地图操作!
(当然,还有其他可能的方法可以在F#中解决这个问题 - map
函数可以返回一个空列表 - 但是结果的推断类型将是'c list
所以这也是是另一种地图)。
答案 3 :(得分:2)
是的,通常你会期望map
保持形状(因此保持大小)。但是对于集合,这显然不能保持一般,因为集合必须遵守一些额外的法则(比如没有重复的元素 - 所以Set.map (f : X -> bool)
显然不会保留集合的大小,如果它应用于具有两个以上的集合其中的元素)。
答案 4 :(得分:2)
术语地图源于数学,仅指一个函数。就其本身而言,它并未说明结果的表示方式。我认为答案取决于内容被映射的类型。
因此,我的假设无效,或者Set不应被视为用于映射目的的序列。这是什么?
我说这个假设一般无效,但在合理适用的情况下应该适用。例如,如果树需要依赖于包含值的结构,并且一个这样的树映射到另一个树,则无法创建维护树结构的有效结果。
但是,您可以将集合视为用于映射目的的序列,就像可转换为IEnumerable<>
的任何内容一样。只需使用Seq.map
代替Set.map
。