【问题标题】:map() as class member versus map() as independent function? [closed]map() 作为类成员与 map() 作为独立函数? [关闭]
【发布时间】:2018-10-10 12:06:49
【问题描述】:

我刚刚发现映射列表在例如Python 和 Haskell 是这样完成的:

newlist = map(function, somelist)

在例如Kotlin 和 Dart 是这样完成的:

newlist = somelist.map(function)

我想知道每种解决方案相对于其他解决方案有哪些优势? Python/Haskell 实现更“实用”不是吗?

【问题讨论】:

  • 使 python 的 map 功能更少的是可迭代协议,因为它从您正在迭代的结构中抽象出来。在 FP map 中必须保留这个结构。迭代太不精确了。在 FP 中,我们 foldmaptraverse
  • 这个问题可能会吸引固执己见的答案,但也有见识。在我看来,这也是非常具体的。投票决定重新开放。

标签: python haskell functional-programming kotlin map-function


【解决方案1】:

这有点基于意见,我选择的语言是 Python,但我会试一试。

Python 非常重视鸭子类型,尤其是可迭代和序列协议。

当您调用map(function, some_iterable) 时,至少从概念上讲,some_iterable 的类型并不重要,只要您可以从其中一个接一个地提取值,以便将函数应用于它们中的每一个。它可以是一个列表,或者一个元组,或者一个字符串,或者一个生成器......拥有一个全局的map 函数可以确保所有这些都可以工作,即使是你自己编写的通过实现__iter__ 可以迭代的类。

在我看来,在YourClass 中实现可迭代协议要优雅得多,它可以解锁一大堆功能,而不是编写自己的YourClass.map 函数或必须调用list(YourClass_instance).map(function)

另一个例子是str.join 方法。为什么我们写"sep".join(my_list) 而不是my_list.join(sep)?同样的事实是,在构建结果字符串时,您并不真正关心这些值是从列表、集合、元组或任何其他可迭代类型中提取的。 str.join 接受任何可迭代对象。

len 是一个内置函数,原因类似。序列(以及通常大多数容器)可以使用len(my_container) 公开它们的项目数量,只要它们实现__len__ 方法,您不必猜测它是my_container.len()my_container.num_items() 还是@987654338 @。

Here 是与此讨论相关的文章。

【讨论】:

  • 是的,除了 FP 中的 map 是结构保留,而 python 中的 map 不是。如果你真正关心的是你正在映射的东西里面有什么“元素”——这当然经常是足够的——那么这种方法就可以了。它实际上一点也不比collection.asSequence.map 之类的东西更好,尽管你可以在所有其他语言中做得很好。如果你想要一个保留结构的地图,那么你对 python 方法不走运。
  • @Cubic true,您必须手动将 map 的返回值转换为 Python 中所需的任何类型(例如 tuple(map(func, iterable)))。不保留底层可迭代的结构在 Python 中可以正常工作,因为该语言经过精心设计,因此在几乎所有用例中,您要么应该根本不关心或“正确”数据类型以进行进一步处理是一个显而易见的选择。感谢您对 FP 语言的意见,我对这些了解不足。
  • 对于字典、元组和列表,这可以正常工作,但请考虑可以映射的非平面结构,例如树:Node 1 (Node 2 Empty Empty) (Node 3 Empty Empty)。现在假设您想向所有节点添加一个 - 使用结构保留映射您可以做到这一点,在基于可迭代的映射中,无法将树结构从可迭代中恢复。
【解决方案2】:

Python 的map 不仅仅适用于列表;它适用于任何可迭代的。 Python 没有向不同的类添加单独的 map 方法(或向 object 添加无操作的 map 方法并多次覆盖它),而是使用可迭代协议;任何实现__iter__ 的类(提供实现__next__ 的对象)都可以与map 一起使用。

【讨论】:

  • 赞成,但为什么 Kotlin 和 Dart 不同?
  • 因为设计师做出了不同的决定。这里没有正确的决定。
【解决方案3】:

它与“更多功能”没有任何关系,只是一种用法。

Haskell 没有方法,所以

newlist = map function somelist

是唯一的写法。

在 Python 中,map 不保留可迭代对象的结构,而是创建一个新列表 (Python2) 或一个新映射对象 (Python3)。它只是一个常规函数,可以将任何可迭代对象作为参数,因此它不附加到特定对象。 (附带说明,map 并不是一个特别流行的函数,它被认为更“pythonic”来使用列表或生成器理解)。

在 Kotlin 中,所有可迭代对象都实现方法 map。与 Python 中它只是一个常规函数不同,它是一个常规(可覆盖)方法,并按原样使用。

这里真正的区别在于,在 Kotlin 中,我们可以用更优化的版本覆盖它,而在 Python 中我们不能。这可能是更多的 OOP,但它并没有真正减少功能。

【讨论】:

    【解决方案4】:

    Python/Haskell 实现更“实用”不是吗?

    不多。 Kotlin 语法不太适合组合,但是...

    您可以将方法调用链接在一起(例如somelist.map(f).map(g)),而不是组合(例如(map f . map g) somelist)。这要求链接对象支持map,因此如果您要编写自己的列表组合器,则必须将它们注入到该对象中。由于 Kotlin 支持extension methods,因此您仍然可以避免耦合数据类型和高阶列表组合器(这通常是面向对象编程的一个缺点)。

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-10-03
    • 2018-01-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多