Say I have a higher kinded type
SuperMap[Key[_],Value[_]]`.
Suppose now that I had something even more specific that required that the type parameter for Key
must match that for Value
; that is, something like:
SuperDuperMap[T, Key[T], Value[T]]
Further suppose that I didn't want just any T
, but a very specific one where T <: OtherT
SuperDuperPooperMap[T <: OtherT, Key[T], Value[T]]
Can this be done in Scala? Is this just generally a bad idea? Is there an equivalent way of doing this that's easier to read/write/use?
You can pass through with a language such as OCaml, Scala, Haskell, PureScript, or one of a few others. However, users of Java, C#, F#, Elm, and many others may proceed no further, and must turn back here.
What Is Higher-Kinded Type? A higher-kinded type is a type that abstracts over some type that, in turn, abstracts over another type. It's a way to generically abstract over entities that take type constructors. They allow us to write modules that can work with a wide range of objects.
Rust does not have higher-kinded-types. For example, functor (and thus monad) cannot be written in Rust.
A higher kinded type is a concept that reifies a type constructor as an actual type. A type constructor can be thought of in these analogies: like a function in the type universe. as a type with a "hole" in it. as a container containing type(s)
Your declaration already works as supposed to, i.e. you're restricting the type of T
as well as Key
and Value
. The way you've written it, however, scala will complain if you issue something like
scala> class Foo[T <: OtherT, Key[T], Value[T]]
defined class Foo
scala> new Foo[SpecialOtherT, Key[SpecialOtherT], Value[SpecialOtherT]]
<console>:13: error: Key[SpecialOtherT] takes no type parameters, expected: one
new Foo[SpecialOtherT, Key[SpecialOtherT], Value[SpecialOtherT]]
because the types of both Key
and Value
are already given by your former declaration. Hence this will work
scala> new Foo[SpecialOtherT, Key, Value]
res20: Foo[SpecialOtherT,Key,Value] = Foo@3dc6a6fd
which is probably not want you want. You could do it like this
scala> class Foo[T <: OtherT, K <: Key[T], V <: Value[T]]
defined class Foo
scala> new Foo[SpecialOtherT, Key[SpecialOtherT], Value[SpecialOtherT]]
res21: Foo[SpecialOtherT,Key[SpecialOtherT],Value[SpecialOtherT]] = Foo@7110506e
At the bottom line, since the types of Key
and Value
depend solely on T
it is somewhat superfluous to have all that redundant information when working with Foo
. So why not use an inner type declaration like so:
class Foo[T <: OtherT] {
type K = Key[T]
type V = Value[T]
}
Then you'd have access to types K
and V
from within the class but wouldn't need to type it everytime you create a new answer:
scala> new Foo[SpecialOtherT]
res23: Foo[SpecialOtherT] = Foo@17055e90
scala> new Foo[Int]
<console>:11: error: ...
Can this be done in Scala?
What do you mean? You just did!
Is this just generally a bad idea?
Why would it be? In fact that's a great idea! This is what higher-kinded types are for.
Is there an equivalent way of doing this that's easier to read/write/use?
Reading - reads pretty well to me.
Writing - write/test/compile once, use everywhere.
Using - The compiler will reconstruct (infer) the types "everywhere".
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With