当编码工厂用于生成'X'类项目的容器时如何统一处理Scala更高级的类型, [英] how to generically handle Scala Higher-kinded types when coding factories for generating containers of items of type 'X'

查看:89
本文介绍了当编码工厂用于生成'X'类项目的容器时如何统一处理Scala更高级的类型,的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在通过本教程中的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, 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.

解决方案

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆