你可以在ruby中执行以下操作:
l = [[1, 2], [3, 4], [5, 6]]
m = l.map {|(a, b)| a+b}
但你不能在scala中执行以下操作:
val a = List((1, 2), (3, 4), (5, 6))
a.map((f, s) => f + s)
<console>:9: error: wrong number of parameters; expected = 1
a.map((f, s) => f + s)
相反,你必须这样做:
a.map { case (f, s) => f + s }
我发现这个相当罗嗦,因为scala定义了一个“元组”类型,我期待它也能在它之上提供语法糖,以便像上面那样隐式匹配。是否有一些深层原因导致不支持这种匹配?有更优雅的方式吗?
答案 0 :(得分:5)
原因是您尝试使用的语法已经具有意义。当高阶函数需要双参数函数时使用它。例如,使用reduce
或fold
:
List(1,2,3).reduce((a,b) => a+b)
可以通过定义自己的隐式方法来实现更清洁的方法:
import scala.collection.generic.CanBuildFrom
import scala.collection.GenTraversableLike
implicit class EnrichedWithMapt2[A, B, Repr](val
self: GenTraversableLike[(A, B), Repr]) extends AnyVal {
def mapt[R, That](f: (A, B) => R)(implicit bf: CanBuildFrom[Repr, R, That]) = {
self.map(x => f(x._1, x._2))
}
}
然后你可以这样做:
val a = List((1, 2), (3, 4), (5, 6))
a.mapt((f, s) => f + s) // List(3, 7, 11)
你可以做一些其他技巧,比如使用tupled
,但它们并没有真正帮助你解决你描述的情况:
val g = (f: Int, s: Int) => f + s
a.map(g.tupled)
或者只是
a.map(((f: Int, s: Int) => f + s).tupled)
答案 1 :(得分:4)
如果您有更多时间,您甚至可以使用含义执行以下操作:
val _1 = { t: { def _1: Int } => t._1 }
val _2 = { t: { def _2: Int } => t._2 }
implicit class HighLevelPlus[A](t: A => Int) {
def +(other: A => Int) = { a: A => t(a) + other(a) }
def *(other: A => Int) = { a: A => t(a) * other(a) }
}
val a = List((1, 2), (3, 4), (5, 6))
a map _1 + _2
monad和关键字for
和yield
的另一种可能性:
val a = List((1, 2), (3, 4), (5, 6))
for((i, j) <- a) yield i + j
但这可能不是你喜欢的解决方案。
答案 2 :(得分:2)
是否有一些深层原因导致不支持这种匹配?
是的,因为在Scala中,语法
(f, s) =>
表示带有2个参数的匿名函数。
有更优雅的方式吗?
(有些诙谐的回答。)使用Haskell,其中\(f, s) ->
实际上是指以元组为参数的函数。
答案 3 :(得分:0)
您可以使用_1
的{{1}},_2
属性获得所需的效果
Tuple