views:

185

answers:

3

Array programming languages (also known as vector or multidimensional languages) generalize operations on scalars to apply transparently to vectors, matrices, and higher dimensional arrays.

Is it possible to achieve this kind of code reuse in Scala?

+5  A: 

There isn't any real way to auto-lift Scala operations, as would you would need to to support array programming languages like APL and J. The closest thing to array auto-lifting in Scala is implicit conversions, and that's not quite right. Scala implicit conversions go the opposite way, converting the targets of the operations, rather than the operations themselves. Even then, Scala implicit conversions don't chain, so even if you could lift a scalar operation to a vector (which you can't), that wouldn't automatically lift it to a 2-D or higher array.

In short, doing APL/J-ish calculation in Scala is going to involve seeing the "map" and "flatMap" methods a lot, explicitly called (as well as fold, reduce, scan, and all the other usual suspects). One benefit is that you can code those operations as for-comprehensions in Scala, which can give some admirable clarity for these sort of batch operations over collections.

Dave Griffith
+5  A: 

Is something like scalala what you're looking for?

Steve Lianoglou
+5  A: 

It's entirely possible (I've done so myself) with appropriate implicits, though the result is not always as utterly seamless as a language that has been designed from the ground up that way.

For example, suppose you want to treat arrays of integers as vectors and want to be able to add them to each other and to scalars. You have to define the operation yourself--Scala can't guess what + should mean on an array. (Good thing, too, because * doesn't usually have the obvious element-by-element meaning on matrices, and it means something else again when it comes to convolution!) You can

class ArraysAdd(a: Array[Int]) {
  def +(i: Int) = a.map(_ + i)
  def +(b: Array[Int]) = {
    if (b.length==a.length) (a,b).zipped.map(_ + _).toArray
    else throw new IllegalArgumentException
  }
}
class ScalarAddsToArray(i: Int) {
  def +(a: Array[Int]) = a.map(_ + i)
}
implicit def array2addable(a: Array[Int]) = new ArraysAdd(a)
implicit def scalar2arrayaddable(i: Int) = new ScalarAddsToArray(i)

and then you can do math on arrays of integers:

scala> Array(1,2,3) + 5
res2: Array[Int] = Array(6, 7, 8)

scala> Array(1,7) + Array(3,2)
res3: Array[Int] = Array(4, 9)

scala> 4 + Array(-2,-3,-1)
res4: Array[Int] = Array(2, 1, 3)

If you want to cover all data types it gets trickier (you need to use generics and Numeric at least--or write a code generator to cover the cases you need), and for efficiency you might want to create a custom "matrix" class instead of sticking with raw arrays that you keep wrapping with extra functionality.

This covers basic operations. For mathematical functions like math.sqrt, if you don't mind typing a map sqrt instead of sqrt(a) then you don't need to do anything. Otherwise, you can overload them all yourself; tedious, but it then lets you use them transparently.

Or you could use a library that has already done much of this for you. (Scalala is the best candidate I know of for matrices.)

Rex Kerr