2012-10-02 43 views
3

我试图在斯卡拉模拟代数半环。我遇到了类型转换问题,这使得看起来不可能在Scala中做我想做的事情。我希望有人能指引我理解我误解的Scala输入系统的方面。如何在Scala中使用运行时工厂对象来实现半实现?

(请长设置为这个问题承受的。我已经削减下来,就像我可以。)

半环超过其定义二进制加法(+)和乘法一组项目(*)运算符及其标识元素,分别称为零和一。例如,Integer Semiring定义在整数上,其中+和*是来自算术和零的标准操作,一个是整数0和1.一个更奇特的例子是布尔半环,它是根据值True和False定义的,其中+是逻辑或,*是逻辑与,零是假,一个是真。

为了建模,我定义了一个特征来指定适当的二元运算符。

trait SemiringElement { 
    /** 
    * The element type 
    */ 
    type E 
    /** 
    * The type returned by the the addition and multiplication operators 
    */ 
    type R <: SemiringElement 
    val value: E 

    def +(that: R): R 

    def *(that: R): R 

    override def toString = value.toString 
} 

案例类实例化特定半环的元素。例如,布尔半环看起来像这样。

case class BooleanSemiringElement(init: Boolean) extends SemiringElement { 
    type E = Boolean 
    type R = BooleanSemiringElement 
    val value = init 

    def +(that: BooleanSemiringElement#R) = BooleanSemiringElement(value || that.value) 

    def *(that: BooleanSemiringElement#R) = BooleanSemiringElement(value && that.value) 
} 

我还有一个指定零和一个元素的Semiring特征。

trait Semiring { 
    type E <: SemiringElement 
    /** 
    * The addition identity 
    */ 
    val zero: E 
    /** 
    * The multiplication identity 
    */ 
    val one: E 
} 

特定的半环对象返回零和一个适当类型的元素。

object BooleanSemiring extends Semiring { 
    type E = BooleanSemiringElement 

    val zero = BooleanSemiringElement(false) 
    val one = BooleanSemiringElement(true) 
} 

的半环的对象基本上是工厂单身知道如何返回适当类型的识别元素。

我希望能够编写一般用于半环元素的算法。我使用Semiring工厂对象,以便能够在运行时指定特定的半环,而不是编译时间。例如,假设我有一个对象在字符串和半环元素之间保持一个映射。

class ElementMap(s: Semiring) { 
    val m = mutable.Map[String, SemiringElement]() 
} 

如果我实例化这个,象这样一个电话:

val x = new ElementMap(BooleanSemiring) 

我想x.m是一个与字符串> BooleanSemiringElement地图。问题是我所拥有的实际上是一个String-> SemiringElement映射。

scala> val x = new ElementMap(BooleanSemiring) 
x: ElementMap = [email protected] 
scala> x.m 
res2: scala.collection.mutable.Map[String,SemiringElement] = Map() 
scala> x.m("one") = BooleanSemiring.one 
scala> x.m("one") + BooleanSemiring.one 
<console>:12: error: type mismatch; 
found : BooleanSemiring.one.type (with underlying type BooleanSemiring.BooleanSemiringElement) 
required: _1.R where val _1: SemiringElement 
       x.m("one") + BooleanSemiring.one 
            ^

如果我愿意在编译时指定类型,而不是运行时我可以做的元素类型的通用像这样:

class ElementMap[BooleanSemiring]... 

但后来我需要一个工厂方法来创建所有不同类型的ElementMap对象。将工厂智慧融入Semiring特质使其更具建筑意义。我想可以说是这样的:

class ElementMap(s: Semiring) { 
    val m = mutable.Map[String, s.E]() 
} 

是:创建一个从字符串由供给构造的半环对象返回的元素类型E的地图。我无法弄清楚如何做到这一点。我尝试了各种语法技巧和隐式转换无济于事。

有没有办法写一个在运行时配置了Semiring构造函数参数的ElementMap,还是我采用了错误的方法?我是新来的Scala,并试图以斯卡拉式的方式做事。我觉得自己已经在这里闯入了一个角落,但我不确定这个失误究竟在哪里。

回答

0

您是否尝试过捕获具体类型s作为类型参数?

scala> class ElementMap[S <: Semiring](s: S) { 
    | val m = collection.mutable.Map[String, S#E]() 
    | } 
defined class ElementMap 

scala> val x = new ElementMap(BooleanSemiring) 
x: ElementMap[BooleanSemiring.type] = [email protected] 

scala> x.m("one") = BooleanSemiring.one 

scala> x.m("one") + BooleanSemiring.one 
res0: BooleanSemiringElement = true 

你就可以用元素类型类似的东西:

scala> class ElementMap[SE <: SemiringElement](s: Semiring { type E = SE }) { 
    | val m = collection.mutable.Map[String, SE]() 
    | } 
defined class ElementMap 

scala> val x = new ElementMap(BooleanSemiring) 
x: ElementMap[BooleanSemiringElement] = [email protected] 

scala> x.m("one") = BooleanSemiring.one 

scala> x.m("one") + BooleanSemiring.one 
res1: BooleanSemiringElement = true 

与您的版本的问题是,你把自己的所有类型的信息有关s - 从的ElementMap的角度来看,它只是一个Semiring

(作为一个侧面说明,通过类型类特设多态可能是解决斯卡拉这个问题更自然的方式。例如,见Scalaz 7表示类似的代数结构的方式。)

+0

感谢。即席多态似乎确实是针对这种情况。我现在正在阅读。斯卡拉兹有一个具体的例子来解决这个问题吗? –

+0

'Monoid'可能是最接近的。 –