假设我要像功能添加map到斯卡拉List,沿着线的东西list mapmap f,其功能适用f于每个元素list的两倍.(一个更严重的例子可能是实现并行或分布式地图,但我不想被那个方向的细节分心.)
我的第一种方法是
object MapMap {
implicit def createFancyList[A](list: List[A]) = new Object {
def mapmap(f: A => A): List[A] = { list map { a: A => f(f(a)) } }
}
}
Run Code Online (Sandbox Code Playgroud)
现在这很好用
scala> import MapMap._
import MapMap._
scala> List(1,2,3) mapmap { _ + 1 }
res1: List[Int] = List(3, 4, 5)
Run Code Online (Sandbox Code Playgroud)
当然除了这只是为ListS,而且也没有理由我们不应该想这对任何工作Traverseable,具有map功能,例如SetS或Stream秒.所以第二次尝试看起来像
object MapMap2 {
implicit def …Run Code Online (Sandbox Code Playgroud) 我会用Scala示例来问这个问题,但很可能这会影响其他允许混合命令和函数样式的语言.
这是一个简短的例子(更新,见下文):
def method: Iterator[Int] {
// construct some large intermediate value
val huge = (1 to 1000000).toList
val small = List.fill(5)(scala.util.Random.nextInt)
// accidentally use huge in a literal
small.iterator filterNot ( huge contains _ )
}
Run Code Online (Sandbox Code Playgroud)
现在iterator.filterNot懒惰地工作,这很棒!因此,我们希望返回的迭代器不会消耗太多内存(实际上是O(1)).然而,可悲的是,我们犯了一个可怕的错误:因为filterNot它是懒惰的,所以它保留了对函数文字的引用huge contains _.
因此,虽然我们认为该方法在运行时需要大量内存,并且该方法可以在方法终止后立即释放,但实际上内存会被卡住,直到我们忘记返回Iterator.
(我只是犯了这样一个错误,这需要很长时间才能找到!你可以抓住这些东西看堆堆...)
避免此问题的最佳做法是什么?
似乎唯一的解决方案是仔细检查在范围结束时存活的函数文字,以及捕获的中间变量.如果您构建一个非严格的集合并计划返回它,这有点尴尬.任何人都可以想到一些不错的技巧,特定于Scala或其他方式,避免这个问题,让我写出漂亮的代码?
更新:我之前给出的例子是愚蠢的,正如huynhjl的答案所示.它曾经是:
def method: Iterator[Int] {
val huge = (1 to 1000000).toList // construct some large intermediate value
val n = huge.last // do some calculation …Run Code Online (Sandbox Code Playgroud) (我正在使用Scala nightlies,并在2.8.0b1 RC4中看到相同的行为.我是Scala的新手.)
我有两个SortedMap我想组成的联盟.这是我想要使用的代码:
import scala.collection._
object ViewBoundExample {
class X
def combine[Y](a: SortedMap[X, Y], b: SortedMap[X, Y]): SortedMap[X, Y] = {
a ++ b
}
implicit def orderedX(x: X): Ordered[X] = new Ordered[X] { def compare(that: X) = 0 }
}
Run Code Online (Sandbox Code Playgroud)
这里的想法是'隐含'语句意味着Xs可以转换为Ordered[X]s,然后将SortedMaps 组合成另一个SortedMap,而不仅仅是一个映射.
当我编译时,我得到了
sieversii:scala-2.8.0.Beta1-RC4 scott$ bin/scalac -versionScala compiler version
2.8.0.Beta1-RC4 -- Copyright 2002-2010, LAMP/EPFL
sieversii:scala-2.8.0.Beta1-RC4 scott$ bin/scalac ViewBoundExample.scala
ViewBoundExample.scala:8: error: type arguments [ViewBoundExample.X] do not
conform to method …Run Code Online (Sandbox Code Playgroud) 我想要一种方便的方法来生成Iterable一个初始对象和一个从当前对象生成下一个对象的函数,它消耗O(1)内存(即,它不会缓存旧结果;如果你想迭代一个第二次,必须再次应用该功能).
它似乎没有图书馆支持.在Scala 2.8中,该方法scala.collection.Iterable.iterate具有签名
def iterate [A] (start: A, len: Int)(f: (A) ? A) : Iterable[A]
Run Code Online (Sandbox Code Playgroud)
因此,它要求您提前指定您感兴趣的迭代函数应用程序的数量,并且我对文档的理解是Iterable.iterate实际上立即计算所有这些值.另一方面,该方法scala.collection.Iterator.iterate具有签名
def iterate [T] (start: T)(f: (T) ? T) : Iterator[T]
Run Code Online (Sandbox Code Playgroud)
这看起来不错,但我们只得到一个Iterator不提供的种种便利map,filter和朋友.
是否有方便的库方法来生产我想要的东西?
如果不,
有人可以建议使用'口语'Scala代码吗?
总而言之,给定一个初始对象a: A和一个函数f: A => A,我想生成一个TraversableLike(例如,可能是一个Iterable)生成a, f(a), f(f(a)), ...,并使用O(1)内存map,filter等等也返回O(1)的函数的函数.记忆.
请注意以下代码
trait Example {
type O
def apply(o: O)
def f(o: O) = this.apply(o)
}
Run Code Online (Sandbox Code Playgroud)
在Scala编译好.我希望我可以apply照常离开,写作def f(o: O) = this(o).但是,这会产生令人兴奋的错误消息
type mismatch; found : o.type (with underlying type Example.this.O)
required: _31.O where val _31: Example
possible cause: missing arguments for method or constructor
Run Code Online (Sandbox Code Playgroud)
任何人都可以向我解释发生了什么事吗?
我的Scala 2.9.1项目现在发出176个警告,几乎完全像这样:
[warn] Not a simple type:
[warn] Type: _29.type#source.type forSome { type _29.type <: Ontology.this.TruncationFunctor } (class class scala.tools.nsc.symtab.Types$ExistentialType)
[warn] Transformed: class xsbti.api.Existential
Run Code Online (Sandbox Code Playgroud)
(它从较少开始,但我的编码风格似乎引发了这个警告,因为我越来越多了.)
任何人都可以向我解释这个警告意味着什么,以及我应该如何避免它?编译器不会发出任何行号,所以我甚至不确定它究竟来自哪里.
我在Scala 2.9.2中遇到麻烦,实现了一个声明依赖返回类型的方法.以下代码
object DependentTypesQuestion {
def ??? = throw new UnsupportedOperationException
trait X {
trait Y
}
trait Z {
def z(x: X): x.Y
}
object Z extends Z {
override def z(x: X): x.Y = ???
}
}
Run Code Online (Sandbox Code Playgroud)
2.9.2下编译时会产生以下错误消息:
overriding method z in trait Z of type (x: DependentTypesQuestion.X)x.Y; method z has incompatible type
Run Code Online (Sandbox Code Playgroud)
在2.10.0-M4中,问题似乎已得到修复,但遗憾的是我的项目现在已经与2.9相关联.
是否可以在2.9.2中解决此问题?
(或者,是否有任何2.9.3的前景,其中包括2.10的后向移植修复?)
有时在Scala中我发现我得到与路径依赖类型相关的类型不匹配,但我可以轻易地推断出事实上类型是一致的.这是一个简单的例子:
trait Foo { trait Bar }
object Main extends App {
val foo1 = new Foo { }
val foo2 = foo1
def turkle(x: foo1.Bar) {}
turkle(new foo2.Bar {})
}
Run Code Online (Sandbox Code Playgroud)
它给出:"类型不匹配;找到:需要Main.foo2.Bar的java.lang.Object:Main.foo1.Bar".
当然现在的路径Main.foo1.Bar和Main.foo2.Bar必须一致,因为我们写的val foo2 = foo1.我们可以通过将最后一行更改为来验证这一点
turkle((new foo2.Bar {}).asInstanceOf[foo1.Bar])
Run Code Online (Sandbox Code Playgroud)
这两个编译和运行没有例外.
Scala可以自动执行这样的推理吗?如果是这样,我怎么能做到这一点?
(如果没有,是否有任何前景可以将类型系统扩展到这个方向?)
我会注意到,有时斯卡拉确实出现执行这种推理.假设我trait Foo改为object Foo:
object Foo { trait Bar }
object Main extends App {
val foo1 = Foo
val foo2 = foo1
def turkle(x: foo1.Bar) …Run Code Online (Sandbox Code Playgroud) 人们会期望并希望如果你要求Mathematica找到多项式的根,它应该给出相同的(近似的)答案,无论你是否象征性地做这个,然后找到这些确切答案的数值近似值,或者你是否用数字表示.这是一个例子(在Mathematica 7OS X上运行),这种情况严重失败:
poly = -112 + 1/q^28 + 1/q^26 - 1/q^24 - 6/q^22 - 14/q^20 - 25/q^18 -
38/q^16 - 52/q^14 - 67/q^12 - 81/q^10 - 93/q^8 - 102/q^6 - 108/
q^4 - 111/q^2 - 111 q^2 - 108 q^4 - 102 q^6 - 93 q^8 - 81 q^10 -
67 q^12 - 52 q^14 - 38 q^16 - 25 q^18 - 14 q^20 - 6 q^22 - q^24 +
q^26 + q^28;
Total[q^4 /. …Run Code Online (Sandbox Code Playgroud) 我只是将我的一些代码更新到2.9.0,而且我遇到了一个问题.我有一个特性,我称之为"NonStrictIterable"(基本上,一切都应该尽可能地懒惰 - NonStrictIterable之外的代码本身不应该运行,直到某人实际要求一个元素).
但是在2.9.0中,我似乎无法覆盖flatMap.这是一个减少版本,显示错误:
import scala.collection.generic.CanBuildFrom
trait NonStrictIterable[A] extends Iterable[A] { self =>
def iterator: Iterator[A]
override def flatMap[B, That](f: A => TraversableOnce[B])(implicit bf: CanBuildFrom[Iterable[A], B, That]): That = {
new NonStrictIterable[B] {
def iterator = self.iterator flatMap { a: A => f(a).toIterable.iterator }
}.asInstanceOf[That]
}
}
Run Code Online (Sandbox Code Playgroud)
这曾经在2.9.0之前工作,但现在我得到"方法flatMap覆盖任何东西".查看Iterable.flatMap的方法签名,我看到TraversableOnce类型签名已更改为enTraversableOnce.做出相应的改变
import scala.collection.GenTraversableOnce
import scala.collection.generic.CanBuildFrom
trait NonStrictIterable[A] extends Iterable[A] { self =>
def iterator: Iterator[A]
override def flatMap[B, That](f: A => GenTraversableOnce[B])(implicit bf: CanBuildFrom[Iterable[A], B, That]): That = { …Run Code Online (Sandbox Code Playgroud) 在Scala 2.10.0-M4中
object X
def f(e: Either[Int, X.type]) = e match {
case Left(i) => i
case Right(X) => 0
}
Run Code Online (Sandbox Code Playgroud)
得到:
warning: match may not be exhaustive.
It would fail on the following input: Right(<not X>)
Run Code Online (Sandbox Code Playgroud)
它是否正确?当然这场比赛实际上是详尽无遗的.
(同时,回到Scala 2.9.X我们得到了
error: pattern type is incompatible with expected type;
found : object X
required: X.type
case Right(X) => 0
Run Code Online (Sandbox Code Playgroud)
这可能是一个错误.)
singleton scala pattern-matching non-exhaustive-patterns scala-2.10