Scala Python yield
ステートメントに相当するもの)で実装することは可能ですか?使用されている関数のローカル状態を記憶しています呼び出されるたびに次の値を「生成」しますか?
再帰関数をイテレータに変換するために、このようなものが必要でした。このような並べ替え:
# this is python
def foo(i):
yield i
if i > 0:
for j in foo(i - 1):
yield j
for i in foo(5):
print i
ただし、foo
はより複雑な場合があり、非循環オブジェクトグラフで再帰します。
追加編集:より複雑な例を追加しましょう(ただし、まだ単純です):単純な再帰関数を記述して、処理を進めます。
// this is Scala
def printClass(clazz:Class[_], indent:String=""): Unit = {
clazz match {
case null =>
case _ =>
println(indent + clazz)
printClass(clazz.getSuperclass, indent + " ")
for (c <- clazz.getInterfaces) {
printClass(c, indent + " ")
}
}
}
理想的には、いくつかのステートメントを簡単に変更して、イテレーターとして機能させることができるライブラリーが欲しいです。
// this is not Scala
def yieldClass(clazz:Class[_]): Iterator[Class[_]] = {
clazz match {
case null =>
case _ =>
sudoYield clazz
for (c <- yieldClass(clazz.getSuperclass)) sudoYield c
for (c <- clazz.getInterfaces; d <- yieldClasss(c)) sudoYield d
}
}
継続がそれを可能にするようですが、私はshift/reset
の概念を理解していません。継続は最終的にメインコンパイラーに入り、ライブラリーの複雑さを抽出することは可能でしょうか?
編集2:チェック リッチの答え 他のスレッドで。
Pythonジェネレーターはすばらしいですが、それらを複製することはScalaで実行するための最良の方法ではありません。たとえば、次のコードはあなたが望むものと同等の仕事をします:
def classStream(clazz: Class[_]): Stream[Class[_]] = clazz match {
case null => Stream.empty
case _ => (
clazz
#:: classStream(clazz.getSuperclass)
#::: clazz.getInterfaces.toStream.flatMap(classStream)
#::: Stream.empty
)
}
その中でストリームは遅延生成されるので、要求されるまで要素を処理しません。要求されるまで、これを実行して確認できます。
def classStream(clazz: Class[_]): Stream[Class[_]] = clazz match {
case null => Stream.empty
case _ => (
clazz
#:: { println(clazz.toString+": super"); classStream(clazz.getSuperclass) }
#::: { println(clazz.toString+": interfaces"); clazz.getInterfaces.toStream.flatMap(classStream) }
#::: Stream.empty
)
}
結果は、結果のIterator
に対して.iterator
を呼び出すだけで、Stream
に変換できます。
def classIterator(clazz: Class[_]): Iterator[Class[_]] = classStream(clazz).iterator
foo
を使用したStream
定義は、次のようにレンダリングされます。
scala> def foo(i: Int): Stream[Int] = i #:: (if (i > 0) foo(i - 1) else Stream.empty)
foo: (i: Int)Stream[Int]
scala> foo(5) foreach println
5
4
3
2
1
0
別の方法としては、さまざまな反復子を連結して、事前に計算しないように注意します。次に、実行の追跡に役立つデバッグメッセージの例を示します。
def yieldClass(clazz: Class[_]): Iterator[Class[_]] = clazz match {
case null => println("empty"); Iterator.empty
case _ =>
def thisIterator = { println("self of "+clazz); Iterator(clazz) }
def superIterator = { println("super of "+clazz); yieldClass(clazz.getSuperclass) }
def interfacesIterator = { println("interfaces of "+clazz); clazz.getInterfaces.iterator flatMap yieldClass }
thisIterator ++ superIterator ++ interfacesIterator
}
これはあなたのコードにかなり近いです。 sudoYield
の代わりに、私は定義を持っているので、必要に応じてそれらを連結します。
だから、これは答えではありませんが、ここで間違った木を吠えていると思います。 Python in Scalaで書くのは非生産的です。同じ目的を達成するScalaイディオムでもっと頑張ってください。
別の継続プラグインベースのソリューション、今回は多かれ少なかれカプセル化されたジェネレータータイプ
import scala.continuations._
import scala.continuations.ControlContext._
object Test {
def loopWhile(cond: =>Boolean)(body: =>(Unit @suspendable)): Unit @suspendable = {
if (cond) {
body
loopWhile(cond)(body)
} else ()
}
abstract class Generator[T] {
var producerCont : (Unit => Unit) = null
var consumerCont : (T => Unit) = null
protected def body : Unit @suspendable
reset {
body
}
def generate(t : T) : Unit @suspendable =
shift {
(k : Unit => Unit) => {
producerCont = k
if (consumerCont != null)
consumerCont(t)
}
}
def next : T @suspendable =
shift {
(k : T => Unit) => {
consumerCont = k
if (producerCont != null)
producerCont()
}
}
}
def main(args: Array[String]) {
val g = new Generator[Int] {
def body = {
var i = 0
loopWhile(i < 10) {
generate(i)
i += 1
}
}
}
reset {
loopWhile(true) {
println("Generated: "+g.next)
}
}
}
}
これを一般的な方法で行うには、 継続プラグイン が必要だと思います。
単純な実装(フリーハンド、コンパイル/チェックされていない):
_def iterator = new {
private[this] var done = false
// Define your yielding state here
// This generator yields: 3, 13, 0, 1, 3, 6, 26, 27
private[this] var state: Unit=>Int = reset {
var x = 3
giveItUp(x)
x += 10
giveItUp(x)
x = 0
giveItUp(x)
List(1,2,3).foreach { i => x += i; giveItUp(x) }
x += 20
giveItUp(x)
x += 1
done = true
x
}
// Well, "yield" is a keyword, so how about giveItUp?
private[this] def giveItUp(i: Int) = shift { k: (Unit=>Int) =>
state = k
i
}
def hasNext = !done
def next = state()
}
_
何が起こっているのかと言うと、shift
への呼び出しは、それが呼び出された場所から、呼び出されたreset
ブロックの終わりまでの制御フローをキャプチャします。これは、k
引数をシフト関数に入れます。
したがって、上記の例では、各giveItUp(x)
はx
の値(その時点まで)を返し、残りの計算をstate
変数に保存します。 hasNext
およびnext
メソッドによって外部から駆動されます。
穏やかに行ってください、これは明らかにこれを実装する恐ろしい方法です。しかし、コンパイラーが手元になければ、私は夜遅くにできることが最善です。
Scalaのfor (e <- Producer) f(e)
形式のforループはforeach
呼び出しに変換され、iterator
/next
には直接変換されません。
foreach
では、イテレータのnext
で必要になるため、オブジェクトの作成を線形化して1か所に配置する必要はありません。コンシューマー関数f
は、必要な場所(オブジェクトが作成される場所)に正確に複数回挿入できます。
これにより、ScalaのTraversable
/foreach
を使用して、ジェネレーターのユースケースの実装が単純かつ効率的になります。
最初のFoo-example:
case class Countdown(start: Int) extends Traversable[Int] {
def foreach[U](f: Int => U) {
var j = start
while (j >= 0) {f(j); j -= 1}
}
}
for (i <- Countdown(5)) println(i)
// or equivalent:
Countdown(5) foreach println
最初のprintClass-example:
// v1 (without indentation)
case class ClassStructure(c: Class[_]) {
def foreach[U](f: Class[_] => U) {
if (c eq null) return
f(c)
ClassStructure(c.getSuperclass) foreach f
c.getInterfaces foreach (ClassStructure(_) foreach f)
}
}
for (c <- ClassStructure(<foo/>.getClass)) println(c)
// or equivalent:
ClassStructure(<foo/>.getClass) foreach println
またはインデント付き:
// v2 (with indentation)
case class ClassWithIndent(c: Class[_], indent: String = "") {
override def toString = indent + c
}
implicit def Class2WithIndent(c: Class[_]) = ClassWithIndent(c)
case class ClassStructure(cwi: ClassWithIndent) {
def foreach[U](f: ClassWithIndent => U) {
if (cwi.c eq null) return
f(cwi)
ClassStructure(ClassWithIndent(cwi.c.getSuperclass, cwi.indent + " ")) foreach f
cwi.c.getInterfaces foreach (i => ClassStructure(ClassWithIndent(i, cwi.indent + " ")) foreach f)
}
}
for (c <- ClassStructure(<foo/>.getClass)) println(c)
// or equivalent:
ClassStructure(<foo/>.getClass) foreach println
出力:
class scala.xml.Elem
class scala.xml.Node
class scala.xml.NodeSeq
class Java.lang.Object
interface scala.collection.immutable.Seq
interface scala.collection.immutable.Iterable
interface scala.collection.immutable.Traversable
interface scala.collection.Traversable
interface scala.collection.TraversableLike
interface scala.collection.generic.HasNewBuilder
interface scala.collection.generic.FilterMonadic
interface scala.collection.TraversableOnce
interface scala.ScalaObject
interface scala.ScalaObject
interface scala.collection.generic.GenericTraversableTemplate
interface scala.collection.generic.HasNewBuilder
interface scala.ScalaObject
interface scala.ScalaObject
interface scala.collection.generic.GenericTraversableTemplate
interface scala.collection.generic.HasNewBuilder
interface scala.ScalaObject
interface scala.collection.TraversableLike
interface scala.collection.generic.HasNewBuilder
interface scala.collection.generic.FilterMonadic
interface scala.collection.TraversableOnce
interface scala.ScalaObject
interface scala.ScalaObject
interface scala.Immutable
interface scala.ScalaObject
interface scala.collection.Iterable
interface scala.collection.Traversable
interface scala.collection.TraversableLike
interface scala.collection.generic.HasNewBuilder
interface scala.collection.generic.FilterMonadic
interface scala.collection.TraversableOnce
interface scala.ScalaObject
interface scala.ScalaObject
interface scala.collection.generic.GenericTraversableTemplate
interface scala.collection.generic.HasNewBuilder
interface scala.ScalaObject
interface scala.ScalaObject
interface scala.collection.generic.GenericTraversableTemplate
interface scala.collection.generic.HasNewBuilder
interface scala.ScalaObject
interface scala.collection.IterableLike
interface scala.Equals
interface scala.collection.TraversableLike
interface scala.collection.generic.HasNewBuilder
interface scala.collection.generic.FilterMonadic
interface scala.collection.TraversableOnce
interface scala.ScalaObject
interface scala.ScalaObject
interface scala.ScalaObject
interface scala.ScalaObject
interface scala.collection.generic.GenericTraversableTemplate
interface scala.collection.generic.HasNewBuilder
interface scala.ScalaObject
interface scala.collection.IterableLike
interface scala.Equals
interface scala.collection.TraversableLike
interface scala.collection.generic.HasNewBuilder
interface scala.collection.generic.FilterMonadic
interface scala.collection.TraversableOnce
interface scala.ScalaObject
interface scala.ScalaObject
interface scala.ScalaObject
interface scala.ScalaObject
interface scala.collection.Seq
interface scala.PartialFunction
interface scala.Function1
interface scala.ScalaObject
interface scala.ScalaObject
interface scala.collection.Iterable
interface scala.collection.Traversable
interface scala.collection.TraversableLike
interface scala.collection.generic.HasNewBuilder
interface scala.collection.generic.FilterMonadic
interface scala.collection.TraversableOnce
interface scala.ScalaObject
interface scala.ScalaObject
interface scala.collection.generic.GenericTraversableTemplate
interface scala.collection.generic.HasNewBuilder
interface scala.ScalaObject
interface scala.ScalaObject
interface scala.collection.generic.GenericTraversableTemplate
interface scala.collection.generic.HasNewBuilder
interface scala.ScalaObject
interface scala.collection.IterableLike
interface scala.Equals
interface scala.collection.TraversableLike
interface scala.collection.generic.HasNewBuilder
interface scala.collection.generic.FilterMonadic
interface scala.collection.TraversableOnce
interface scala.ScalaObject
interface scala.ScalaObject
interface scala.ScalaObject
interface scala.ScalaObject
interface scala.collection.generic.GenericTraversableTemplate
interface scala.collection.generic.HasNewBuilder
interface scala.ScalaObject
interface scala.collection.SeqLike
interface scala.collection.IterableLike
interface scala.Equals
interface scala.collection.TraversableLike
interface scala.collection.generic.HasNewBuilder
interface scala.collection.generic.FilterMonadic
interface scala.collection.TraversableOnce
interface scala.ScalaObject
interface scala.ScalaObject
interface scala.ScalaObject
interface scala.ScalaObject
interface scala.ScalaObject
interface scala.collection.generic.GenericTraversableTemplate
interface scala.collection.generic.HasNewBuilder
interface scala.ScalaObject
interface scala.collection.SeqLike
interface scala.collection.IterableLike
interface scala.Equals
interface scala.collection.TraversableLike
interface scala.collection.generic.HasNewBuilder
interface scala.collection.generic.FilterMonadic
interface scala.collection.TraversableOnce
interface scala.ScalaObject
interface scala.ScalaObject
interface scala.ScalaObject
interface scala.ScalaObject
interface scala.ScalaObject
interface scala.collection.SeqLike
interface scala.collection.IterableLike
interface scala.Equals
interface scala.collection.TraversableLike
interface scala.collection.generic.HasNewBuilder
interface scala.collection.generic.FilterMonadic
interface scala.collection.TraversableOnce
interface scala.ScalaObject
interface scala.ScalaObject
interface scala.ScalaObject
interface scala.ScalaObject
interface scala.xml.Equality
interface scala.Equals
interface scala.ScalaObject
interface scala.ScalaObject
interface scala.ScalaObject
interface scala.ScalaObject
interface Java.io.Serializable
Dsl.scala はあなたが探しているものです。
乱数ジェネレータを作成するとします。生成された数値は、遅延評価された無限ストリームに格納する必要があります。これは、組み込みのドメイン固有のキーワードYield
を使用して作成できます。
import com.thoughtworks.dsl.keys.Yield
def xorshiftRandomGenerator(seed: Int): Stream[Int] = {
val tmp1 = seed ^ (seed << 13)
val tmp2 = tmp1 ^ (tmp1 >>> 17)
val tmp3 = tmp2 ^ (tmp2 << 5)
!Yield(tmp3)
xorshiftRandomGenerator(tmp3)
}
他の例は Scaladoc にあります。