Scala & for comprehensions:将 map、flatmap 和 filter 作为依赖于伴随对象的实例方法实现时会出现编译错误

Scala & for comprehensions: Compile errors when implementing map, flatmap, and filter as instance methods that rely on a companion object

对于任何有问题的 synax,我提前表示歉意。我正在学习一门新语言,非常感谢您的帮助!

出于学习的目的,我正在尝试设置一个自定义列表实现(名为 Mlist,用于 'my list'),它可以与 Scala 的理解一起使用。在尝试这样做时,我 运行 遇到了一个让我难过的编译错误。

这是有问题的代码:

sealed trait Mlist[+A] {
  def map[A,B](f: A => B): Mlist[B]
  def flatMap[A,B](f: A => Mlist[B]): Mlist[B]
  def filter[A](f: A => Boolean): Mlist[A]
}

case object Mnil extends Mlist[Nothing] {

  def map[A,B](f: A => B): Mlist[B] = {
    Mnil
  }

  def flatMap[A, B](f: A => Mlist[B]): Mlist[B] = {
    Mnil
  }

  def filter[A](f: A => Boolean): Mlist[A] = {
    Mnil
  }

}

case class Mcons[+A](head: A, tail: Mlist[A]) extends Mlist[A] {

  def map[A,B](f: A => B): Mlist[B] = {
    Mlist.map(this)(f)
  }

  def flatMap[A,B](f: A => Mlist[B]): Mlist[B] = {
    Mlist.flatMap(this)(f)
  }

  def filter[A](f: A => Boolean): Mlist[A] = {
    Mlist.filter(this)(f)
  }

}

object Mlist {

  def map[A,B](l: Mlist[A])(f: A => B): Mlist[B] = {
    foldRight(l, Mnil: Mlist[B])((h, t) => Mcons(f(h), t))
  }

  def filter[A](as: Mlist[A])(f: A => Boolean): Mlist[A] = {
    foldRight(as, Mnil: Mlist[A])((a, acc) => if (f(a)) Mcons(a, acc) else acc)
  }

  def flatMap[A, B](as: Mlist[A])(f: A => Mlist[B]): Mlist[B] = {
    concat(map(as)(f))
  }
}

object Mlist {

  def map[A,B](l: Mlist[A])(f: A => B): Mlist[B] = {
    foldRight(l, Mnil: Mlist[B])((h, t) => Mcons(f(h), t))
  }

  def filter[A](as: Mlist[A])(f: A => Boolean): Mlist[A] = {
    foldRight(as, Mnil: Mlist[A])((a, acc) => if (f(a)) Mcons(a, acc) else acc)
  }

  def flatMap[A, B](as: Mlist[A])(f: A => Mlist[B]): Mlist[B] = {
    concat(map(as)(f))
  }

}

基本思想是有一个trait来定义我的两个Mlist实现的方法类。我没有为 map 之类的东西重新实现实例方法,而是尝试调用我的帮助程序对象以重用它的方法。

这是我看到的编译错误:

[error] /Users/jb/Desktop/dev/personal/functional-programming-scala/src/main/scala/Ch3Lists.scala:31: type mismatch;
[error]  found   : A(in method map) => B
[error]  required: A(in class Mcons) => B
[error]     Mlist.map(this)(f)
[error]                     ^
[error] /Users/jb/Desktop/dev/personal/functional-programming-scala/src/main/scala/Ch3Lists.scala:35: type mismatch;
[error]  found   : A(in method flatMap) => Mlist[B]
[error]  required: A(in class Mcons) => Mlist[B]
[error]     Mlist.flatMap(this)(f)
[error]                         ^
[error] /Users/jb/Desktop/dev/personal/functional-programming-scala/src/main/scala/Ch3Lists.scala:39: type mismatch;
[error]  found   : A(in method filter) => Boolean
[error]  required: A(in class Mcons) => Boolean
[error]     Mlist.filter(this)(f)
[error]                        ^
[error] /Users/jb/Desktop/dev/personal/functional-programming-scala/src/main/scala/Ch3Lists.scala:39: type mismatch;
[error]  found   : Mlist[A(in class Mcons)]
[error]  required: Mlist[A(in method filter)]
[error]     Mlist.filter(this)(f)

而且,如果它真的有用,下面是我最终打算实现的(未经测试且可能完全功能失调的)理解:

def combos(list: Mlist[A]): Mlist[Mlist[A]] = {
  for {
    el <- list
    combo <- combos(tail(list))
  } yield {
    setHead(el, combo)
  }
}

任何人都可以告诉我我的编译错误是什么意思以及如何解决它们吗?

您正在使用 Mlist.mapMlist.flatMap 和 [=20] 中的同名类型参数隐藏 Mlist 特征中定义的类型参数 A =] 方法:

sealed trait Mlist[+A] {
//                  ↑
// this is a type parameter named `A`
  def map[A,B](f: A => B): Mlist[B]
  //      ↑
  // this is a completely different, totally unrelated type parameter, 
  // confusingly also named `A`
  def flatMap[A,B](f: A => Mlist[B]): Mlist[B]
  def filter[A](f: A => Boolean): Mlist[A]
}

Scala 在错误消息中告诉您这一点,它在同名 As 和 which 参数名称后的括号中告诉您=22=]它在谈论:

[error] /Users/jb/Desktop/dev/personal/functional-programming-scala/src/main/scala/Ch3Lists.scala:31: type mismatch;
[error]  found   : A(in method map) => B
//                  ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
[error]  required: A(in class Mcons) => B
//                  ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
[error]     Mlist.map(this)(f)
[error]                     ^
[error] /Users/jb/Desktop/dev/personal/functional-programming-scala/src/main/scala/Ch3Lists.scala:35: type mismatch;
[error]  found   : A(in method flatMap) => Mlist[B]
//                  ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
[error]  required: A(in class Mcons) => Mlist[B]
//                  ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
[error]     Mlist.flatMap(this)(f)
[error]                         ^
[error] /Users/jb/Desktop/dev/personal/functional-programming-scala/src/main/scala/Ch3Lists.scala:39: type mismatch;
[error]  found   : A(in method filter) => Boolean
//                  ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
[error]  required: A(in class Mcons) => Boolean
//                  ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
[error]     Mlist.filter(this)(f)
[error]                        ^
[error] /Users/jb/Desktop/dev/personal/functional-programming-scala/src/main/scala/Ch3Lists.scala:39: type mismatch;
[error]  found   : Mlist[A(in class Mcons)]
//                        ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
[error]  required: Mlist[A(in method filter)]
//                        ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
[error]     Mlist.filter(this)(f)

也许,如果您在所有地方都使用新名称并且不隐藏任何内容,错误消息可能会变得更清楚:

sealed trait Mlist[+A] {
  def map[B, C](f: B => C): Mlist[C]
  def flatMap[D, E](f: D => Mlist[E]): Mlist[E]
  def filter[F](f: F => Boolean): Mlist[F]
}

case object Mnil extends Mlist[Nothing] {
  def map[G, H](f: G => H): Mlist[H] = this
  def flatMap[I, J](f: I => Mlist[J]): Mlist[J] = this
  def filter[K](f: K => Boolean): Mlist[K] = this
}

case class Mcons[+L](head: L, tail: Mlist[L]) extends Mlist[L] {
  def map[M, N](f: M => N): Mlist[N] = Mlist.map(this)(f)
  def flatMap[O, P](f: O => Mlist[P]): Mlist[P] = Mlist.flatMap(this)(f)
  def filter[Q](f: Q => Boolean): Mlist[Q] = Mlist.filter(this)(f)
}

object Mlist {
  def map[R, S](l: Mlist[R])(f: R => S): Mlist[S] = 
    foldRight(l, Mnil: Mlist[S])((h, t) => Mcons(f(h), t))

  def filter[T](as: Mlist[T])(f: T => Boolean): Mlist[T] = 
    foldRight(as, Mnil: Mlist[T])((a, acc) => if (f(a)) Mcons(a, acc) else acc)

  def flatMap[U, V](as: Mlist[U])(f: U => Mlist[V]): Mlist[V] =
    concat(map(as)(f))
}

这给出了以下错误消息:

<console>:24: error: type mismatch;
 found   : M => N
 required: L => N
             def map[M, N](f: M => N): Mlist[N] = Mlist.map(this)(f)
                                                                  ^
<console>:25: error: type mismatch;
 found   : O => Mlist[P]
 required: L => Mlist[P]
             def flatMap[O, P](f: O => Mlist[P]): Mlist[P] = Mlist.flatMap(this)(f)
                                                                                 ^
<console>:26: error: type mismatch;
 found   : Q => Boolean
 required: L => Boolean
             def filter[Q](f: Q => Boolean): Mlist[Q] = Mlist.filter(this)(f)
                                                                           ^
<console>:26: error: type mismatch;
 found   : Mlist[L]
 required: Mlist[Q]
             def filter[Q](f: Q => Boolean): Mlist[Q] = Mlist.filter(this)(f)
                                                                    ^

我希望现在可以清楚地看到您的错误来自何处。

请注意,您实际上从未在任何地方使用特征或 class 的类型参数,您 总是 仅使用方法的类型参数。这肯定听起来很可疑;您需要实际使用这些类型参数!

sealed trait Mlist[+A] {
  def map[B](f: A => B): Mlist[B]
  def flatMap[B](f: A => Mlist[B]): Mlist[B]
  def filter(f: A => Boolean): Mlist[A]
}

case object Mnil extends Mlist[Nothing] {
  def map[A, B](f: A => B): Mlist[B] = this
  def flatMap[A, B](f: A => Mlist[B]): Mlist[B] = this
  def filter[A](f: A => Boolean): Mlist[A] = this
}

case class Mcons[+A](head: A, tail: Mlist[A]) extends Mlist[A] {
  def map[B](f: A => B): Mlist[B] = Mlist.map(this)(f)
  def flatMap[B](f: A => Mlist[B]): Mlist[B] = Mlist.flatMap(this)(f)
  def filter(f: A => Boolean): Mlist[A] = Mlist.filter(this)(f)
}

object Mlist {
  def map[A, B](l: Mlist[A])(f: A => B): Mlist[B] = 
    foldRight(l, Mnil: Mlist[B])((h, t) => Mcons(f(h), t))

  def filter[A](as: Mlist[A])(f: A => Boolean): Mlist[A] = 
    foldRight(as, Mnil: Mlist[A])((a, acc) => if (f(a)) Mcons(a, acc) else acc)

  def flatMap[A, B](as: Mlist[A])(f: A => Mlist[B]): Mlist[B] =
    concat(map(as)(f))
}

顺便说一句,我认为你的抽象是错误的方式:当然,外部对象如 Mlist 单例对象应该 知道内部Mcons 个对象并操纵它们!一个对象应该知道如何操纵自己,而其他人不应该知道这一点。事实上,您的抽象奇怪地混合在一起:Mnil 知道如何处理自身,但 Mcons 对象不知道。这样看起来更清醒:

case class Mcons[+A](head: A, tail: Mlist[A]) extends Mlist[A] {
  def map[B](f: A => B): Mlist[B] = foldRight(Mnil: Mlist[B])((h, t) => Mcons(f(h), t))
  def flatMap[B](f: A => Mlist[B]): Mlist[B] = concat(map(f))
  def filter(f: A => Boolean): Mlist[A] = 
    foldRight(Mnil: Mlist[A])((a, acc) => if (f(a)) Mcons(a, acc) else acc)
}

object Mlist {
  def map[A, B](l: Mlist[A])(f: A => B): Mlist[B] = l map f
  def filter[A](as: Mlist[A])(f: A => Boolean): Mlist[A] = as filter f
  def flatMap[A, B](as: Mlist[A])(f: A => Mlist[B]): Mlist[B] = as flatMap f
}

注意到每对中的方法,实现方法和委托方法如何变得更简单了吗?这是一个好兆头。