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.
Array[Byte]is not a type class. Are you trying to say thatAandBmust be equal toArray[Byte]? That'd be like doingf :: (a ~ [Byte]) => a -> a -> ain Haskell - you can do that with the right extensions, but it's pretty nonsensical since it's equivalent tof :: [Byte] -> [Byte] -> [Byte], so why (pretend to) have the type variable at all?sendMessage(producer: Eval[KafkaProducer[Array[Byte], Array[Byte]]])(pr: Eval[ProducerRecord[Array[Byte], Array[Byte]]]). As you can I see, I have to writeArray[Byte]four times.Num a => a -> a -> adoes in Haskell (it's not a shortcut forNum -> Num -> Num, which isn't even legal unless you define a type namedNum). You constrain a type parameter to a typeclass using[TypeParameter : TypeClass], butArray[Byte]is not a typeclass. To avoid typing, you can just use a type alias.