1

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?

6
  • 5
    I wonder how this is “the same”... seems to be two very different functions. Commented Nov 12, 2017 at 12:29
  • 1
    What are you trying to do exactly? Array[Byte] is not a type class. Are you trying to say that A and B must be equal to Array[Byte]? That'd be like doing f :: (a ~ [Byte]) => a -> a -> a in Haskell - you can do that with the right extensions, but it's pretty nonsensical since it's equivalent to f :: [Byte] -> [Byte] -> [Byte], so why (pretend to) have the type variable at all? Commented Nov 12, 2017 at 12:30
  • What I want to do is, avoid writing type several times, like: sendMessage(producer: Eval[KafkaProducer[Array[Byte], Array[Byte]]])(pr: Eval[ProducerRecord[Array[Byte], Array[Byte]]]). As you can I see, I have to write Array[Byte] four times. Commented Nov 12, 2017 at 12:42
  • How to constraint, a type parameter to a typeclass in scala? Commented Nov 12, 2017 at 12:43
  • 3
    @zero_coding "How to avoid writing the same type name multiple times?" and "How to constraint a type parameter to a typeclass?" are two fundamentally different questions, which makes me think that you don't understand what Num a => a -> a -> a does in Haskell (it's not a shortcut for Num -> Num -> Num, which isn't even legal unless you define a type named Num). You constrain a type parameter to a typeclass using [TypeParameter : TypeClass], but Array[Byte] is not a typeclass. To avoid typing, you can just use a type alias. Commented Nov 12, 2017 at 12:47

2 Answers 2

6

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.

Sign up to request clarification or add additional context in comments.

Comments

0

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]]) =...

1 Comment

The Byte class if final, so there can't be any subclasses of it. So you might as well do sendMessage(producer: Eval[KafkaProducer[Array[Byte]])(pr: Eval[KafkaProducer[Array[Byte]])

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.