Scala:在一个简单的自定义类型中实现map和withFilter

cer*_*ran 12 monads for-loop scala

我正在学习Scala,并且已经不得不发现monad的概念对于我目前的知识水平来说有点过于复杂.但是,我的目标至少是创建一个非常简单的类,可以与for表达式一起使用,另外还有一个过滤器.

根据我的理解,以下规则适用:

  • 为了使自定义类型可用于for表达式的生成器(其中生成器仅生成简单变量),它需要实现map.
  • 如果还应该使用过滤器,那么该类型也必须实现withFilter.

我的最小班级看起来像这样:

class Grid(private val fields: IndexedSeq[Field])

class Field(val name: String, val isVisible: Boolean)
Run Code Online (Sandbox Code Playgroud)

我想要实现的是能够做到以下几点:

for(f <- grid) yield f.name // needs map
for(f <- grid; if f.isVisisble) yield f.name // needs map + withFilter
Run Code Online (Sandbox Code Playgroud)

但是,我很难找到那种简单的例子.如果解决方案"适应"上面显示的两个类,而不是可以应用于任何类的通用解决方案,那就没问题.对这个简单的例子展示实现肯定会对我有所帮助.感谢任何帮助,谢谢.

编辑:

正如李指出的那样,我的意图似乎只适用于泛型类型.我认为如果我忘记了课程Field并重新定义Grid如下,那将更有意义:

class Grid[E](private val fields: IndexedSeq[E])
Run Code Online (Sandbox Code Playgroud)

Jas*_*r-M 7

在这种情况下,您可以将map调用传递给包装的集合fields.
因为withFilter你可以调用filter方法fields,但我认为这并不完全符合withFilter应该具有的语义.

case class Grid[E](private val fields: IndexedSeq[E]) {
  def map[R](f: E => R): Grid[R] = new Grid(fields map f)
  def withFilter(p: E => Boolean): Grid[E] = new Grid(fields filter p)
}
Run Code Online (Sandbox Code Playgroud)

对你所要求的更正确但更复杂的实现是:

case class Grid[E](private val fields: IndexedSeq[E]) {
  def map[R](f: E => R): Grid[R] = new Grid(fields map f)
  def withFilter(p: E => Boolean): WithFilter = new WithFilter(p)

  class WithFilter(p: E => Boolean) {
    def map[R](f: E => R): Grid[R] = new Grid(fields.withFilter(p).map(f))
    def withFilter(q: E => Boolean): WithFilter = new WithFilter(x => p(x) && q(x))
  }
}
Run Code Online (Sandbox Code Playgroud)

这样,withFilter会像预期的那样懒散地工作.