gpt4 book ai didi

python - 在 Scala 中实现 'yield' 的首选方法是什么?

转载 作者:IT老高 更新时间:2023-10-28 20:50:15 30 4
gpt4 key购买 nike

我正在为博士研究编写代码并开始使用 Scala。我经常要做文本处理。我习惯了 Python,它的“yield”语句对于在大型、通常不规则结构的文本文件上实现复杂的迭代器非常有用。其他语言(例如 C#)中也存在类似的结构,这是有充分理由的。

是的,我知道以前有过这方面的主题。但它们看起来像是被破解(或至少解释不好)的解决方案,它们显然不能很好地工作并且通常具有不明确的限制。我想写这样的代码:

import generator._

def yield_values(file:String) = {
generate {
for (x <- Source.fromFile(file).getLines()) {
# Scala is already using the 'yield' keyword.
give("something")
for (field <- ":".r.split(x)) {
if (field contains "/") {
for (subfield <- "/".r.split(field)) { give(subfield) }
} else {
// Scala has no 'continue'. IMO that should be considered
// a bug in Scala.
// Preferred: if (field.startsWith("#")) continue
// Actual: Need to indent all following code
if (!field.startsWith("#")) {
val some_calculation = { ... do some more stuff here ... }
if (some_calculation && field.startsWith("r")) {
give("r")
give(field.slice(1))
} else {
// Typically there will be a good deal more code here to handle different cases
give(field)
}
}
}
}
}
}
}

我想看看实现 generate() 和 give() 的代码。 BTW give() 应该被命名为 yield() 但 Scala 已经使用了这个关键字。

我认为,由于我不明白的原因,Scala 延续可能无法在 for 语句中工作。如果是这样,generate() 应该提供一个尽可能接近 for 语句的等效函数,因为带有 yield 的迭代器代码几乎不可避免地位于 for 循环内。

请,我不希望得到以下任何答案:

  1. 'yield' 糟透了,延续更好。 (是的,一般来说,你可以用延续做更多的事情。但它们很难理解,99% 的情况下,迭代器就是你想要或需要的全部。如果 Scala 提供了许多强大的工具,但它们太难使用了在实践中,该语言不会成功。)
  2. 这是重复的。 (请参阅我上面的评论。)
  3. 您应该使用流、延续、递归等来重写您的代码(请参阅#1。我还要补充一点,从技术上讲,您也不需要 for 循环。就此而言,从技术上讲,您绝对可以做任何事情您需要使用 SKI combinators。)
  4. 你的函数太长了。把它分成小块,你就不需要“产量”了。无论如何,您必须在生产代码中执行此操作。 (首先,“你不需要'yield'”在任何情况下都是值得怀疑的。其次,这不是生产代码。第三,对于这样的文本处理,经常将函数分解成更小的部分——尤其是当语言强制你这样做,因为它缺乏有用的结构——只会让代码更难理解。)
  5. 使用传入的函数重写您的代码。(从技术上讲,是的,您可以这样做。但结果不再是迭代器,并且链式迭代器比链式函数好得多。一般来说,一种语言不应该强制我以不自然的风格写作——当然,Scala 的创造者普遍相信这一点,因为他们提供了大量的语法糖。)
  6. 用这个、那个或其他方式重写你的代码,或者我刚刚想到的其他一些很酷、很棒的方式。

最佳答案

您的问题的前提似乎是您完全想要 Python 的产量,并且您不希望任何其他合理的建议在 Scala 中以不同的方式做同样的事情。如果这是真的,而且它对你很重要,为什么不使用 Python 呢?这是一门很好的语言。除非你的博士学位。是计算机科学专业,使用 Scala 是您论文的重要组成部分,如果您已经熟悉 Python,并且非常喜欢它的一些功能和设计选择,为什么不改用它呢?

无论如何,如果您真的想学习如何在 Scala 中解决您的问题,那么事实证明,对于您拥有的代码,分隔延续是多余的。您所需要的只是 flatMapped 迭代器。

这就是你的做法。

// You want to write
for (x <- xs) { /* complex yield in here */ }
// Instead you write
xs.iterator.flatMap { /* Produce iterators in here */ }

// You want to write
yield(a)
yield(b)
// Instead you write
Iterator(a,b)

// You want to write
yield(a)
/* complex set of yields in here */
// Instead you write
Iterator(a) ++ /* produce complex iterator here */

就是这样!您的所有案例都可以归结为这三种中的一种。

在你的情况下,你的例子看起来像

Source.fromFile(file).getLines().flatMap(x =>
Iterator("something") ++
":".r.split(x).iterator.flatMap(field =>
if (field contains "/") "/".r.split(field).iterator
else {
if (!field.startsWith("#")) {
/* vals, whatever */
if (some_calculation && field.startsWith("r")) Iterator("r",field.slice(1))
else Iterator(field)
}
else Iterator.empty
}
)
)

附: Scala 确实继续;它是这样完成的(通过抛出无堆栈(轻量级)异常来实现):

import scala.util.control.Breaks._
for (blah) { breakable { ... break ... } }

但这不会得到你想要的,因为 Scala 没有你想要的 yield 。

关于python - 在 Scala 中实现 'yield' 的首选方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7303166/

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