gpt4 book ai didi

python - Scala 相当于 Python 生成器?

转载 作者:IT老高 更新时间:2023-10-28 20:27:47 25 4
gpt4 key购买 nike

是否可以在 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 的概念。 continuation 最终会进入主编译器吗?是否有可能提取出库中的复杂性?

编辑 2:查看Rich's answer在另一个线程中。

最佳答案

虽然 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
)
}

只需在生成的 Stream 上调用 .iterator 即可将结果转换为 Iterator:

def classIterator(clazz: Class[_]): Iterator[Class[_]] = classStream(clazz).iterator

使用 Streamfoo 定义将被渲染为:

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 习语上更加努力。

关于python - Scala 相当于 Python 生成器?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2137619/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com