0

I have tried to add methods like "multiply by a scalar" to Array[T] via a typeclass, to mimic numpy functionality. I have looked at an example, which works and adds a "show" method with no parameters to Array[T]. However, in my case, I find that I am unable to add methods with parameters, e.g. array.*(2.0).

Using Scala 2.12.6.

How can I make this code work?

package numpy

trait BehaveLikeNumpy[T] {
  def *(a: Array[T], x: T): Array[T]
}

object BehaveLikeNumpyInstances {

  def apply[T](implicit bln: BehaveLikeNumpy[T]): BehaveLikeNumpy[T] = bln

  object ops {
    def *[T: BehaveLikeNumpy](a: Array[T], x: T): Array[T] = BehaveLikeNumpyInstances[T].*(a, x)

    implicit class BehaveLikeNumpyOps[T: BehaveLikeNumpy](a: Array[T]) {
      def *(x: T) = BehaveLikeNumpyInstances[T].*(a, x)
    }
  }

  implicit val arrayTimes_Double = (a: Array[Double], x: Double) => a.map(y => y * x)
}

package some.pkg
import numpy.BehaveLikeNumpyInstances
import numpy.BehaveLikeNumpyInstances.ops._

val aaa: Array[Double] = (0 until 5).toArray.map(_.toDouble)
aaa.show // Works. See https://blog.scalac.io/2017/04/19/typeclasses-in-scala.html
val s1 = aaa.*(2.0)// Error: value * is not a member of Array[Double]
val s2 = aaa * 2.0 // Error: value * is not a member of Array[Double]

1 Answer 1

2

Firstly you lost type (for transformation of lambda to SAM trait)

implicit val arrayTimes_Double: BehaveLikeNumpy[Double] = 
  (a: Array[Double], x: Double) => a.map(y => y * x)

secondly you lost underscore

import numpy.BehaveLikeNumpyInstances._
Sign up to request clarification or add additional context in comments.

6 Comments

With your proposed changes I get the same errors, plus: type mismatch; found: (Array[Double], Double) => Array[Double]; required: numpy.BehaveLikeNumpy[Double]
What is your Scala? This works in 2.12. In 2.11 you should write arrayTimes_Double: BehaveLikeNumpy[Double] = new BehaveLikeNumpy[Double]... manually instead of the lambda.
Scala 2.12.6. Added it to the post (was not there initially).
No, you can just add def + to trait BehaveLikeNumpy, object ops and implicit class BehaveLikeNumpyOps, manually define implicit val arrayTimes_Double with new without lambda (since BehaveLikeNumpy is no longer a SAM trait) and with the same two imports both + and * should work.
Don't define two lambdas like implicit val arrayTimes_Double.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.