Python 생성기와 동일한 Scala?
yield
사용되는 함수의 로컬 상태를 기억하고 호출 될 때마다 다음 값을 "수율"하는 Python 문과 동일한 것을 Scala에서 구현할 수 있습니까?
재귀 함수를 반복자로 변환하기 위해 이와 같은 것을 갖고 싶었습니다. 다음과 같습니다.
# 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 : 다른 스레드에서 Rich의 대답 을 확인하십시오 .
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
정의가 있고 원하는대로 연결합니다.
그래서 이것은 답이 아니지만, 나는 당신이 여기서 잘못된 나무를 짖고 있다고 생각합니다. Scala에서 Python을 작성하는 것은 비생산적입니다. 동일한 목표를 달성하는 Scala 관용구에서 더 열심히 일하십시오.
이번에는 다소 캡슐화 된 Generator 유형을 사용하는 또 다른 연속 플러그인 기반 솔루션,
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)
}
}
}
}
일반적인 방법으로이를 수행하려면 continuations 플러그인 이 필요하다고 생각합니다 .
순진한 구현 (자유, 컴파일 / 확인되지 않음) :
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-loop 형식 은 / 로 직접 변환되지 않고 호출 로 for (e <- Producer) f(e)
변환됩니다 .foreach
iterator
next
에서 foreach
우리는 객체의 생성을 선형화 할 필요가 없으며 반복자의 next
. 소비자 함수 f
는 정확히 필요한 곳에 (즉, 객체가 생성되는) 여러 번 삽입 될 수 있습니다.
이것은 Scala에서 Traversable
/ 를 사용하여 생성기에 대한 사용 사례를 간단하고 효율적으로 구현 foreach
합니다.
초기 Foo 예제 :
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- 예 :
// 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)
}
Other examples can be found in the Scaladoc.
ReferenceURL : https://stackoverflow.com/questions/2137619/scala-equivalent-to-python-generators
'IT TIP' 카테고리의 다른 글
C ++ 생성자 / 소멸자 상속 (0) | 2021.01.08 |
---|---|
svn 저장소에서 업데이트하면“Could not read chunk size”오류가 반환됩니다. (0) | 2021.01.08 |
Django를 사용하여 SSO (Single Sign On) 구현 (0) | 2021.01.08 |
C ++ 컴파일러는 언제부터 문자열 리터럴 문자 이스케이프에서 두 개 이상의 16 진수를 고려하기 시작 했습니까? (0) | 2021.01.08 |
열거 형 변수 기본값? (0) | 2021.01.08 |