Reputation: 34061
In Haskell, I can constraint a parameter to a type class, for example:
Prelude> f x y = x * y
Prelude> :t f
f :: Num a => a -> a -> a
I was trying to do the same in Scala
as following:
def sendMessage[A: Array[Byte], B: Array[Byte]](producer: Eval[KafkaProducer[A, B]])(pr: Eval[ProducerRecord[A, B]]) =
But the compiler complains:
[error] /home/developer/Desktop/scala/PureProducer/src/main/scala/TheProducer.scala:39:20: Array[Byte] does not take type parameters
[error] def sendMessage[A: Array[Byte], B: Array[Byte]](producer: Eval[KafkaProducer[A, B]])(pr: Eval[ProducerRecord[A, B]]) =
How to constraint a type parameter in Scala?
Upvotes: 1
Views: 2952
Reputation: 370092
In Scala type classes are represented as generic traits whose instances are passed as implicit parameters. As an example take the following Haskell type class:
class Foo a where
foo :: a
bar :: a -> a -> a
f :: Foo a => a -> a
f x = bar foo x
instance Foo Int where
foo = 42
bar x y = x + y
f 23 -- Result: 42 + 23 = 65
The Scala equivalent would look like this:
// class Foo a
trait Foo[A] {
def foo: A
def bar(x: A, y: A): A
}
def f[A](x: A)(implicit foo: Foo[A]) = foo.bar(foo.foo, x)
// instance Foo Int
implicit case object FooInt extends Foo[Int] {
def foo = 42
def bar(x: Int, y: Int) = x + y
}
f(23) // Result: 42 + 23 = 65
There's also a shortcut to define the implicit parameter: def f[A: Foo](x: A)
is short for def f[A](x: A)(implicit _unnamed: Foo[A])
. However this means that you can't access the instance of the type class directly in the body (because you don't give it a name), so it's only useful when all you do is pass the type class instance around to other methods (which can be done implicitly and thus does not require a name).
In Scala the Num
type class is called Numeric
instead, which offers methods like plus
and times
. So to do the same thing as your Haskell example, you can write:
def f[A](x: A, y: A)(implicit num: Numeric[A]) = num.times(x,y)
The reason that your attempt with Array[Byte]
did not work is because Array[Byte]
is not a type class. Specifically the A: Array[Byte]
shorthand expands to this:
def sendMessage[A, B](producer: Eval[KafkaProducer[A, B]])(pr: Eval[ProducerRecord[A, B]])(implicit _unamed1: Array[Byte][A], implicit _unnamed2: Array[Byte][B])
Looking at that it should be clear why that does not work: Array[Byte][A]
just makes no sense.
According to your comments you simply want to avoid writing Array[Byte]
multiple times. This has nothing whatsoever to do with type classes (neither in Haskell nor in Scala). You can simply use a type alias for that.
Upvotes: 6
Reputation: 16224
If you know that always takes an Array, just constraint the inside type, and the types are equal, so you just need one type variable, and then the type you want to be subtype, I'm not sure if Byte can be subtyped so:
def sendMessage[A<:YourClass](producer: Eval[KafkaProducer[Array [A]])(pr: Eval[KafkaProducer[Array [A]]) =...
But I think you can just do in your case:
def sendMessage(producer: Eval[KafkaProducer[Array [Byte]])(pr: Eval[KafkaProducer[Array [Byte]]) =...
Upvotes: 0