首页 文章

什么是Scala的收益?

提问于
浏览
292

我理解Ruby和Python的收益率 . Scala的收益率是多少?

9 回答

  • 12

    它在sequence comprehensions中使用(类似于Python的列表推导和生成器,您也可以使用 yield ) .

    它与 for 结合使用,并将新元素写入结果序列 .

    简单的例子(来自scala-lang

    /** Turn command line arguments to uppercase */
    object Main {
      def main(args: Array[String]) {
        val res = for (a <- args) yield a.toUpperCase
        println("Arguments: " + res.toString)
      }
    }
    

    F#中的相应表达式将是

    [ for a in args -> a.toUpperCase ]
    

    要么

    from a in args select a.toUpperCase
    

    在Linq .

    Ruby的 yield 有不同的效果 .

  • 9

    我认为接受的答案很好,但似乎很多人都未能掌握一些基本要点 .

    首先,Scala的 for 理解等同于Haskell的 do 符号,它只不过是构成多个monadic操作的语法糖 . 由于这句话很可能无法帮助任何需要帮助的人,让我们再试一次...... :-)

    Scala的 for comprehensions是使用map, flatMapfilter 进行多个操作组合的语法糖 . 或 foreach . Scala实际上将 for -表达式转换为对这些方法的调用,因此提供它们的任何类或其子集都可以用于理解 .

    首先,我们来谈谈翻译 . 有非常简单的规则:

    • 这个
    for(x <- c1; y <- c2; z <-c3) {...}
    

    被翻译成

    c1.foreach(x => c2.foreach(y => c3.foreach(z => {...})))
    
    • 这个
    for(x <- c1; y <- c2; z <- c3) yield {...}
    

    被翻译成

    c1.flatMap(x => c2.flatMap(y => c3.map(z => {...})))
    
    • 这个
    for(x <- c; if cond) yield {...}
    

    在Scala 2.7上翻译成

    c.filter(x => cond).map(x => {...})
    

    或者,在Scala 2.8上,进入

    c.withFilter(x => cond).map(x => {...})
    

    如果方法 withFilter 不可用但 filter 是,则回退到前者 . 有关详细信息,请参阅以下部分 .

    • 这个
    for(x <- c; y = ...) yield {...}
    

    被翻译成

    c.map(x => (x, ...)).map((x,y) => {...})
    

    当你看到非常简单的 for 理解时, map / foreach 替代方案看起来确实更好 . 但是,一旦开始编写它们,就很容易迷失在括号和嵌套级别中 . 当这种情况发生时, for 理解通常会更加清晰 .

    我将展示一个简单的例子,故意省略任何解释 . 您可以决定哪种语法更容易理解 .

    l.flatMap(sl => sl.filter(el => el > 0).map(el => el.toString.length))
    

    要么

    for {
      sl <- l
      el <- sl
      if el > 0
    } yield el.toString.length
    

    withFilter

    Scala 2.8引入了一个名为 withFilter 的方法,它的主要区别在于,它不是返回一个新的,已过滤的集合,而是按需过滤 . filter 方法的行为是根据集合的严格性定义的 . 为了更好地理解这一点,让我们看看一些带有 List (严格)和 Stream (非严格)的Scala 2.7:

    scala> var found = false
    found: Boolean = false
    
    scala> List.range(1,10).filter(_ % 2 == 1 && !found).foreach(x => if (x == 5) found = true else println(x))
    1
    3
    7
    9
    
    scala> found = false
    found: Boolean = false
    
    scala> Stream.range(1,10).filter(_ % 2 == 1 && !found).foreach(x => if (x == 5) found = true else println(x))
    1
    3
    

    之所以出现这种差异是因为 filter 会立即应用 List ,返回赔率列表 - 因为 foundfalse . 只有这样才会执行 foreach ,但是,到目前为止,更改 found 是没有意义的,因为 filter 已经执行了 .

    Stream 的情况下,不立即应用该条件 . 相反,当 foreach 请求每个元素时, filter 测试条件,这使 foreach 能够通过 found 影响它 . 为了说清楚,这里是等效的理解代码:

    for (x <- List.range(1, 10); if x % 2 == 1 && !found) 
      if (x == 5) found = true else println(x)
    
    for (x <- Stream.range(1, 10); if x % 2 == 1 && !found) 
      if (x == 5) found = true else println(x)
    

    这导致了许多问题,因为人们期望 if 被视为按需,而不是事先应用于整个集合 .

    Scala 2.8引入了 withFilter ,它始终是非严格的,无论集合的严格程度如何 . 以下示例在Scala 2.8上显示了两个方法的 List

    scala> var found = false
    found: Boolean = false
    
    scala> List.range(1,10).filter(_ % 2 == 1 && !found).foreach(x => if (x == 5) found = true else println(x))
    1
    3
    7
    9
    
    scala> found = false
    found: Boolean = false
    
    scala> List.range(1,10).withFilter(_ % 2 == 1 && !found).foreach(x => if (x == 5) found = true else println(x))
    1
    3
    

    这会产生大多数人期望的结果,而不会改变 filter 的行为方式 . 另外,在Scala 2.7和Scala 2.8之间, Range 从非严格变为严格 .

  • 1

    是的,正如Earwicker所说,'s pretty much the equivalent to LINQ' s select 与Ruby 's and Python' s yield 几乎没什么关系 . 基本上,在C#中你会写的

    from ... select ???
    

    在Scala,你有

    for ... yield ???
    

    同样重要的是要理解 for -comprehensions不仅适用于序列,而且适用于定义某些方法的任何类型,就像LINQ一样:

    • 如果您的类型仅定义 map ,则它允许 for -由单个生成器组成的表达式 .

    • 如果它定义了 flatMap 以及 map ,它允许 for -由多个生成器组成的表达式 .

    • 如果它定义了 foreach ,它允许 for -loops没有yield(包括单个和多个生成器) .

    • 如果它定义 filter ,它允许在 for 表达式中以 if 开头的 for -filter表达式 .

  • 194

    除非你从Scala用户那里得到更好的答案(我不是),这是我的理解 .

    它仅作为以 for 开头的表达式的一部分出现,该表达式指出如何从现有列表生成新列表 .

    就像是:

    var doubled = for (n <- original) yield n * 2
    

    因此每个输入都有一个输出项(尽管我相信有一种方法可以删除重复项) .

    这与其他语言中yield的“命令式延续”完全不同,它提供了一种生成任意长度列表的方法,从一些命令式代码几乎任何结构 .

    (如果你're familiar with C#, it'更接近LINQ's select 运算符而不是 yield return ) .

  • 13

    The keyword yield in Scala is simply syntactic sugar 可以很容易地被 map 替换,详见Daniel Sobral already explained .

    另一方面, yield is absolutely misleading if 您正在寻找类似于those in Python的生成器(或延续) . 有关更多信息,请参阅此SO线程:What is the preferred way to implement 'yield' in Scala?

  • 23

    考虑以下for-comprehension

    val A = for (i <- Int.MinValue to Int.MaxValue; if i > 3) yield i
    

    如下大声朗读可能会有所帮助

    For 每个整数 iif 它大于 3 ,然后 yield (产生) i 并将其添加到列表 A . ”

    就数学而言,上述理解类似于

    set-notation

    可以读作

    For 每个整数
    i
    if 它大于
    3
    ,然后它 is a member 的设置
    A
    . ”

    或者作为


    A
    是所有整数的集合
    i
    ,这样每个
    i
    都大于
    3
    . ”

  • -3

    yield类似于for循环,它有一个我们看不到的缓冲区,对于每个增量,它会不断地将下一个项添加到缓冲区 . 当for循环完成运行时,它将返回所有生成值的集合 . Yield可以用作简单的算术运算符,甚至可以与数组结合使用 . 以下是两个简单的示例,供您更好地理解

    scala>for (i <- 1 to 5) yield i * 3
    

    res:scala.collection.immutable.IndexedSeq [Int] = Vector(3,6,9,12,15)

    scala> val nums = Seq(1,2,3)
    nums: Seq[Int] = List(1, 2, 3)
    
    scala> val letters = Seq('a', 'b', 'c')
    letters: Seq[Char] = List(a, b, c)
    
    scala> val res = for {
         |     n <- nums
         |     c <- letters
         | } yield (n, c)
    

    res:Seq [(Int,Char)] = List((1,a),(1,b),(1,c),(2,a),(2,b),(2,c),( 3,a),(3,b),(3,c))

    希望这可以帮助!!

  • 0
    val aList = List( 1,2,3,4,5 )
    
    val res3 = for ( al <- aList if al > 3 ) yield al + 1
    val res4 = aList.filter(_ > 3).map(_ + 1)
    
    println( res3 )
    println( res4 )
    

    这两段代码是等价的 .

    val res3 = for (al <- aList) yield al + 1 > 3
    val res4 = aList.map( _+ 1 > 3 )
    
    println( res3 ) 
    println( res4 )
    

    这两段代码也是等价的 .

    Map 与收益率一样灵活,反之亦然 .

  • 786

    yield比map()更灵活,请参见下面的示例

    val aList = List( 1,2,3,4,5 )
    
    val res3 = for ( al <- aList if al > 3 ) yield al + 1 
    val res4 = aList.map( _+ 1 > 3 ) 
    
    println( res3 )
    println( res4 )
    

    yield将打印结果如:List(5,6),这很好

    而map()将返回如下结果:List(false,false,true,true,true),这可能不是你想要的 .

相关问题