Scala相当于Haskell的where-clauses?
有可能使用类似于Scala中的where-clause的东西吗?也许有一些我没想到的技巧?
编辑: 感谢您的所有答案,他们非常感激。总结一下: 现在只剩下一个问题:有没有办法将值或函数定义放在使用表达式之后?有时看起来很清楚。这可以通过类或对象的fields / methods来实现,但在方法中似乎不起作用。 迄今为止,答案中还没有提到另外一件事。 where-clause也限制了它们中定义的表达式的范围。我还没有找到一种在Scala中实现这一点的方法。 解决方法
在Hakell中,其中的子句将本地定义保存到函数中。 Scala没有明确的where子句,但通过使用本地的var,val和def可以实现相同的功能。
本地`var`和`val` 在斯卡拉: def foo(x: Int,y: Int): Int = { val a = x + y var b = x * y a - b } 在哈斯克尔 foo :: Integer -> Integer -> Integer foo x y = a - b where a = x + y b = x * y 本地`def` 在斯卡拉 def foo(x: Int,y: Int): Int = { def bar(x: Int) = x * x y + bar(x) } 在哈斯克尔 foo :: Integer -> Integer -> Integer foo x y = y + bar x where bar x = x * x 如果我在Haskell示例中出现任何语法错误,请更正我,因为我目前没有在此计算机上安装Haskell编译器:)。 可以以类似的方式实现更复杂的示例(例如使用两种语言支持的模式匹配)。本地函数具有与其他函数完全相同的语法,只是它们的范围是它们所在的块。 编辑:另见Daniel的这个例子的答案和一些关于这个问题的阐述。 编辑2:增加了关于惰性变量和值的讨论。 懒惰`var`和`val` Edward Kmett的答案正确地指出,Haskell的where子句有懒惰和纯洁。您可以使用延迟变量在Scala中执行非常相似的操作。这些仅在需要时实例化。请考虑以下示例: def foo(x: Int,y: Int) = { print("--- Line 1: "); lazy val lazy1: Int = { print("-- lazy1 evaluated "); x^2} println(); print("--- Line 2: "); lazy val lazy2: Int = { print("-- lazy2 evaluated "); y^2} println(); print("--- Line 3: "); lazy val lazy3: Int = { print("-- lazy3 evaluated ") while(true) {} // infinite loop! x^2 + y^2 } println(); print("--- Line 4 (if clause): "); if (x < y) lazy1 + lazy2 else lazy2 + lazy1 } 这里lazy1,lazy2和lazy3都是懒惰的变量。 lazy3从来没有被实例化(因此这个代码永远不会进入无限循环),并且lazy1和lazy2的实例化顺序取决于函数的参数。例如,当您调用foo(1,2)时,将在lazy2之前实例化lazy1,当您调用foo(2,1)时,将会得到相反的结果。尝试在scala解释器中的代码,看看打印输出! (我不会把它放在这里,因为这个答案已经很久了)。 您可以获得类似的结果,而不是使用非参数函数的延迟变量。在上面的示例中,您可以用def替换每个惰性值,并获得类似的结果。不同之处在于缓存变量(也称为一次评估),但是每次调用def时都会进行评估。 编辑3:增加了关于范围的讨论,看问题。 本地定义的范围 本地定义具有它们被声明的块的范围,如预期的那样(在大多数情况下,在很少的情况下,它们可以逃避块,就像在for循环中使用mid-stream变量绑定一样)。因此,可以使用局部var,val和def来限制表达式的范围。举个例子: object Obj { def bar = "outer scope" def innerFun() { def bar = "inner scope" println(bar) // prints inner scope } def outerFun() { println(bar) // prints outer scope } def smthDifferent() { println(bar) // prints inner scope ! :) def bar = "inner scope" println(bar) // prints inner scope } def doesNotCompile() { { def fun = "fun" // local to this block 42 // blocks must not end with a definition... } println(fun) } } innerFun()和outerFun()都按预期方式运行。 innerFun()中的bar的定义隐藏了包围范围中定义的条。此外,函数fun是其封闭块的本地,因此不能以其他方式使用。方法doesNotCompile()…不编译。有趣的是注意到来自smthDifferent()方法的println()调用打印内部范围。因此,是的,您可以在方法中使用定义之后!我不会推荐,因为我认为这是不好的做法(至少在我看来)。在类文件中,您可以根据需要安排方法定义,但是在使用之前,我会将所有的defs保留在函数中。和vals和vars …好…我发现它使用后把它们尴尬。 还要注意,每个块必须以不带定义的表达式结束,因此您不能在块的末尾具有所有定义。我可能把所有的定义放在一个块的开始处,然后写出所有的逻辑,在该块的末尾产生一个结果。这似乎更自然的方式,而不是: { // some logic // some defs // some other logic,returning the result } 正如我以前所说的,你不能只是//一些defs来结束一个块。这是Scala与Haskell略有不同的地方:)。 编辑4:在使用它们之后对其进行定义,详细说明了Kim的评论。 在使用它们后定义“东西” 这是一个棘手的事情来实现一种有副作用的语言。在纯粹无副作用的世界中,秩序并不重要(方法不依赖于任何副作用)。但是,由于Scala允许副作用,您定义功能的地方很重要。另外,当您定义一个val或var时,必须对右侧进行评估,以便实例化该val。请考虑以下示例: // does not compile :) def foo(x: Int) = { // println *has* to execute now,but // cannot call f(10) as the closure // that you call has not been created yet! // it's similar to calling a variable that is null println(f(10)) var aVar = 1 // the closure has to be created here,// as it cannot capture aVar otherwise def f(i: Int) = i + aVar aVar = aVar + 1 f(10) } 你给的例子是工作,虽然vals是懒惰或他们def def。 def foo(): Int = { println(1) lazy val a = { println("a"); b } println(2) lazy val b = { println("b"); 1 } println(3) a + a } 这个例子也很好地显示了工作中的缓存(尝试改变懒惰val来看看发生什么事情:) 我仍然在一个有副作用的世界中,在使用它们之前,最好坚持使用定义。这样更容易读取源代码。 – Flaviu Cipcigan (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
- scala – 为什么我们必须显式导入具有来自伴随对象的隐式参
- 打字稿 – 为什么我的angular2应用程序初始化两次?
- NG2&4折腾记 --- 记NG2升级NG4 RC1之修正问题跑起来
- Shell重定向与显式文件处理代码
- WebService技术简介
- angularjs – 如何在禁用按钮上显示ui-boostrap工具提示?
- keepalived + haproxy 实现web 双主模型的高可用负载均衡--
- Angular2 - HTTP
- angular – md-autocomplete onSelectionChange两次射击
- angular – 找不到模块:错误:无法解析’./$$_gendir/app/