You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现Scala原生风格的List.map?兼论Functor使用差异

实现Scala原生风格的List.map方法及相关澄清

问题背景

Scala官网曾给出一个重实现List的map方法的示例,调用方式为独立函数式调用:

def strlen(s: String): Int = s.length
map(strlen, List("a", "bb", "ccc"))   // 结果:List(1, 2, 3)

而Scala原生List的map是作为实例方法调用的,风格如下:

List("a","b").map(x => x.length)

实现原生风格的map方法

要实现能以List实例.map(转换函数)方式调用的map,只需将map定义为List类/特质的成员方法,或者通过扩展方法为现有List添加该方法,以下以自定义List为例:

方式1:在List特质中直接定义map

// 自定义List的代数数据类型
sealed trait MyList[+A] {
  // 作为成员方法实现map
  def map[B](f: A => B): MyList[B] = this match {
    case Nil => Nil
    case Cons(head, tail) => Cons(f(head), tail.map(f))
  }
}
case object Nil extends MyList[Nothing]
case class Cons[+A](head: A, tail: MyList[A]) extends MyList[A]

// 伴生对象提供便捷创建方法
object MyList {
  def apply[A](elems: A*): MyList[A] =
    if (elems.isEmpty) Nil
    else Cons(elems.head, apply(elems.tail: _*))
}

// 调用示例
val testList = MyList("a", "bb", "ccc")
println(testList.map(_.length)) // 输出:Cons(1,Cons(2,Cons(3,Nil)))

方式2:通过扩展方法为现有List添加自定义map

如果不想修改原生List的定义,也可以用Scala的扩展方法实现:

extension [A](list: List[A]) {
  def customMap[B](f: A => B): List[B] = list match {
    case Nil => Nil
    case head :: tail => f(head) :: tail.customMap(f)
  }
}

// 调用示例
List("a", "b").customMap(_.length) // 结果:List(1, 2)

关于Functor的澄清

官网示例中的map是作为独立函数实现的,符合函数式编程中Functor抽象的形式(即map: (F[A], A=>B) => F[B]),这种实现是对Functor抽象的具象化。但Scala官方源码中的List.map并没有依赖Functor抽象:

  • Scala标准库的List是直接通过模式匹配(匹配Nil和::)实现map方法,作为类的成员方法存在;
  • 虽然Scala有scala.util.control.Functor trait,但List并未继承它,官方集合设计更偏向面向对象的成员方法风格,Functor的抽象更多由第三方库(如Cats、ZIO Prelude)提供支持。

内容的提问来源于stack exchange,提问作者datnt

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 16:12:46