how to generically handle Scala Higher-kinded types when coding factories for generating containers of items of type 'X'

廉价感情. 提交于 2019-12-24 03:27:23

问题


After working through some examples of Scala Higher-kinded types in this tutorial, I started wondering if it is possible to write a method that generically handles two subclasses of a trait that is defined as a higher-kinded type.

The tutorial defines (a slightly more complex version of) this trait:

trait ContainerFactory[M[_]] { def put[A](x: A): M[A] }

Which I understand as the signature of a type parameterized factory that creates different kinds of containers (Lists, Sets, etc., where the type of container is given by M) and where the type of the object inserted into the container via the put method is given by A. At the invocation site (I think that's the correct term) where you instantiate the container, you specify the type of container you want (as in the line with the comment: //factory for List containers)

val factory = new ContainerFactory[List] { def put[A](x: A) = List(x)  } // factory for List containers
factory.put("dog") // insert an element of type String to factory
res5: List[String] = List(dog)          //  and you get a List of String

factory.put(1)// insert an element of type Int to factory
res6: List[Int] = List(1) // and you get a List of Int

val factory2 = new ContainerFactory[Set] { def put[A](x: A) = Set(x)} // factory for Set containers
factory2.put("dog")
factory2.put(1)

My goal is to create a method that takes a ContainerFactory and an object to put into the generated container. I would like that method to generate the appropriate container (List or Set) parameterized to hold the type of object that I pass in as the second object.

I think a method like the one below would be really cool and useful, but I am having trouble with the Scala syntax to get it to work. In fact, I don't even know if it is possible.

// Code below does not compile
// Method for generating container (of type defined by first arg) that contains the second argument, and 
// which (after instantiation) is parameterized to hold  only objects of that type:

def genContainer[M[T]](factory: ContainerFactory[M], item : T) = {
    factory.put(item)
}


genContainer(factory2, "x")
// desired return value =>    Set[String] = Set(x)

genContainer(factory, 11)
// desired return value =>    List[Int] = List(11)

Note: the error I get when I try to define genContainer is:

<console>:10: error: not found: type T
       def genContainer[M[T]]( factory :  Container[M]  ,  item : T) = {

Note 2: I can define a method like this, which takes a generic ContainerFactory

def genContainer[M[T]](factory:  ContainerFactory[M]) = { }

But when I try to specify the second argument as type T (which is referenced in the parameterization) I get the error about T not found.


回答1:


You were really close:

def genContainer[T, M[_]](factory:  ContainerFactory[M], item: T) = {
    factory.put(item)
}

All you have to do is specify each type parameter as a top-level type parameter! And the compiler is smart enough to deduce these type parameters under many circumstances:

val factory = new ContainerFactory[List] { def put[A](x: A) = List(x)  }
genContainer(factory, "foo") //No need to specify the type parameters!



回答2:


You're very close. The issue is that you need to declare your type parameters separately:

def genContainer[T, M[_]](factory: ContainerFactory[M], item: T) =
  factory.put(item)

This is a little confusing because the following compiles:

def genContainer[M[T]](factory: ContainerFactory[M]) = "whatever"

The scope of the T here is limited to the inside of the M[...], though (see section 4.4 of the language specification for details). This can be convenient when you're declaring fancy bounds like M[T <: Foo[T]], but in general giving the type parameter of the type constructor a name is just noise, and it's best to go with M[_] (which is exactly equivalent to M[A]).



来源:https://stackoverflow.com/questions/29835894/how-to-generically-handle-scala-higher-kinded-types-when-coding-factories-for-ge

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!