当编码工厂用于生成'X'类项目的容器时如何统一处理Scala更高级的类型, [英] how to generically handle Scala Higher-kinded types when coding factories for generating containers of items of type 'X'
问题描述
在通过本教程中的Scala Higher-kinded类型的示例之后, ,我开始想知道是否有可能编写一个方法来统一处理一个特性
被定义为一个更高类型的两个子类。
$ p $ traf ContainerFactory [M [_]] {def put [A ](x:A):M [A]}
我理解为类型的签名创建不同类型容器的参数化工厂( Lists
, Set
s等),其中容器的类型是给定的通过 M
)以及通过put方法插入到容器中的对象的类型由 A
给出。在调用网站(我认为这是正确的术语),你
实例化容器,你指定你想要的容器的类型(如在注释行中: //工厂的List容器)
val factory = new ContainerFactory [List] {def put [A](x: A)= List(x)} //工厂为List容器
factory.put(dog)//向工厂插入String类型的元素
res5:List [String] = List )//你得到一个字符串列表
factory.put(1)//将一个Int类型的元素插入到工厂
res6:List [Int] = List(1)/ /和你得到一个List的Int
val factory2 = new ContainerFactory [Set] {def put [A](x:A)= Set(x)} //工厂的Set容器
factory2.put(dog)
factory2.put(1)
我的目标是创建一个方法,该方法将 ContainerFactory
和一个对象放入生成的容器中。我希望该方法生成适当的容器( List
或 Set
)参数化以保存I作为第二个对象传入。
我认为像下面这样的方法真的很酷且很实用,但是我无法用Scala语法来实现它工作。事实上,我甚至不知道这是否可能。
//下面的代码不会编译
//生成容器(由第一个arg定义的类型)的方法包含第二个参数,
//其中(实例化后)参数化为只保存该类型的对象:
def genContainer [M [T]](factory:ContainerFactory [M] ,item:T)= {
factory.put(item)
}
genContainer(factory2,x)
//所需返回值=> Set [String] = Set(x)
genContainer(factory,11)
//期望的返回值=> List [Int] = List(11)
注意:当我尝试定义 genContainer
是:
< console>:10:error:not found :type T
def genContainer [M [T]](factory:Container [M],item:T)= {
注意2:我可以定义一个像这样的方法,它需要一个通用的 ContainerFactory
def genContainer [M [T]](factory:ContainerFactory [M])= {}
但是,当我尝试指定第二个参数为类型 T
(它在参数化中被引用)时,我得到关于<$ c $ b $> t 找不到。
您真的很接近:
def genContainer [T,M [_]](factory:ContainerFactory [M],item:T)= {
factory.put项目)
}
您需要做的是将每个类型参数指定为top-级别pe参数!在很多情况下,编译器足够聪明地推导出这些类型参数:
val factory = new ContainerFactory [List] {def put [A](x:A)= List(x)}
genContainer(factory,foo)//无需指定类型参数!
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
, Set
s, 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.
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!
这篇关于当编码工厂用于生成'X'类项目的容器时如何统一处理Scala更高级的类型,的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!