scala – 持续和理解 – 什么是不兼容性?

我是新来的 Scala,试图围绕着我的头脑
我正在尝试重现产量返回C#语句.

this post之后,我写了下面的代码

package com.company.scalatest

import scala.util.continuations._;

object GenTest {

  val gen = new Generator[Int] {
    def produce = {
      yieldValue(1)
      yieldValue(2)
      yieldValue(3)
      yieldValue(42)
    }
  }
  // Does not compile :(

  //  val gen2 = new Generator[Int] {
  //    def produce = {
  //      var ints = List(1,2,3,42);
  //
  //      ints.foreach((theInt) => yieldValue(theInt));
  //    }
  //  }

  // But this works?
  val gen3 = new Generator[Int] {
    def produce = {
      var ints = List(1,42);
      var i = 0;
      while (i < ints.length) {
        yieldValue(ints(i));
        i = i + 1;
      }
    }
  }

  def main(args: Array[String]): Unit = {
    gen.foreach(println);
    //    gen2.foreach(println);
    gen3.foreach(println);
  }
}

abstract class Generator[E] {

  var loopFn: (E => Unit) = null

  def produce(): Unit @cps[Unit]

  def foreach(f: => (E => Unit)): Unit = {
    loopFn = f
    reset[Unit,Unit](produce)
  }

  def yieldValue(value: E) =
    shift { genK: (Unit => Unit) =>
      loopFn(value)
      genK(())
      ()
    }
}

你可以看到,gen2被注释掉,因为它没有编译.由于我可以轻松地使用while循环遍历列表的内容(见gen3),所以我预计foreach循环也是一样.

编译错误如下:

no type parameters for method foreach: (f: Int => B)Unit exist so that 
it can be applied to arguments (Int => Unit @scala.util.continuations.cpsParam[Unit,Unit])  
 --- because --- 
argument expression's type is not compatible with formal parameter type;  
found   : Int => Unit @scala.util.continuations.cpsParam[Unit,Unit]  
required: Int => ?B

为什么我得到这个错误,有没有办法解决这个比一个比循环更干净的东西?

谢谢

解决方法

首先让我们来看看gen2编译需要做什么.

object cpsConversions {

  import scala.collection.IterableLike
  import scala.util.continuations._

  implicit def cpsIterable[A,Repr](xs: IterableLike[A,Repr]) = new {
    def cps = new {
      def foreach[B](f: A => Any@cpsParam[Unit,Unit]): Unit@cpsParam[Unit,Unit] = {
        val it = xs.iterator
        while(it.hasNext) f(it.next)
      }
    }
  }
}

object GenTest {

  import cpsConversions.cpsIterable
  val gen2 = new Generator[Int] {
    def produce = {
      var ints = List(1,42)
      ints.cps.foreach((theInt) => yieldValue(theInt))
    }
  }

现在来看看发生了什么.原始gen2无法在以下行中编译:

ints.foreach((theInt) => yieldValue(theInt))

由于yieldValue的类型包含一个@cpsParam注释,所以继承插件将传递给foreach方法函数转换为以下类型之一:

Int => Unit @cpsParam[Unit,Unit]

在列表[Int]的层次结构中,您将看到foreach定义为:

foreach [U] (f: (Int) ⇒ U): Unit

这是一个问题,因为类型不匹配,Scala不知道如何从Int => U到Int =>单位@cpsParam [Unit,Unit].为了解决这个问题,我在一个隐式转换中添加了foreach的cps版本,你可以通过调用任何IterableLike上的cps来访问它.

如果这种隐式转换可以在没有明确的cps调用的情况下完成,那么这将是非常好的,但是我还没有找到一种方法来使Scala编译器识别这种隐式转换的可用性,以将新的foreach复制到列表中.这可能与编译器使用连续插件的顺序有关,但我知道这个过程太少了,以确保.

所以这一切都很好,对foreach有好处.您的问题提到了解,这将需要定义任何过滤器,地图或平面图(取决于您的理解情况).我在上面的评论中已经实现了这些,它扩展了上面的cpsConversions对象,以允许一般的理解.

相关文章

共收录Twitter的14款开源软件,第1页Twitter的Emoji表情 Tw...
Java和Scala中关于==的区别Java:==比较两个变量本身的值,即...
本篇内容主要讲解“Scala怎么使用”,感兴趣的朋友不妨来看看...
这篇文章主要介绍“Scala是一种什么语言”,在日常操作中,相...
这篇文章主要介绍“Scala Trait怎么使用”,在日常操作中,相...
这篇文章主要介绍“Scala类型检查与模式匹配怎么使用”,在日...