سؤال

أحاول تحديد حلقة فئة بقايا عامة في سكالا. يتم تعريف حلقة فئة البقايا بواسطة بعض الحلقة الأساسية (على سبيل المثال الأعداد الصحيحة) ومعامل (مثل اثنين) ، وهي قيمة من الحلقة الأساسية. كل من الحلقات وعناصرها هي كائنات ، وبالتالي فإن نوع المعامل عادة ما يكون نوعًا تابعًا ، اعتمادًا على الحلقة الأساسية. أنا أفهم أن هذا غير مسموح به في Scala (لأسباب وجيهة) ، لذلك أحاول محاكاة ذلك من خلال تقريب النوع والقيام بفحص وقت التشغيل عند إنشاء حلقة فئة البقايا.

تعريف ResidueClassRing مقبول بدون خطأ ، ومع ذلك ، لا يسمح لي Scala بإطفاءها ، للوسيطة two أحصل على رسالة الخطأ

type mismatch;
found   : dependenttypetest.DependentTypeTest.two.type 
(with underlying type dependenttypetest.Integers.Integer)  
required: dependenttypetest.EuclideanRing#E

أفعل شيئا خاطئا؟ هل يمكن أن يكون هذا خطأ في مدقق نوع Scala؟ هل هناك طريقة أفضل لتحديد ResidueClassRing?

هذا هو مع Scala 2.8.0 في Eclipse IDE لـ Helios. حدثت المشكلة بالفعل لمدة 2.7.x. فيما يلي نسخة مبسطة من الكود:

package dependenttypetest


class EuclideanRing
{
  thisRing =>

  type E <: EuclideanRingElement;

  def one: E;

  trait EuclideanRingElement 
  {
    def ring = thisRing;

    def +(b: E): E;
    def %(b: E): E;
  }
}


object Integers extends EuclideanRing
{
  type E = Integer;

  val one: Integer = new Integer(1);

  class Integer(n: Int) extends EuclideanRingElement
  {
    val intValue: Int = n;
    def +(b: Integer): Integer = new Integer(intValue + b.intValue);
    def %(b: Integer): Integer = new Integer(intValue % b.intValue);
  }
}


class ResidueClassRing (val baseRing : EuclideanRing, m : EuclideanRing#E) 
{
  val modulus: baseRing.E = 
    m match {
    case e: baseRing.E if m.ring == baseRing => e;
    case _ => throw new IllegalArgumentException("modulus not from base ring");
    };

  type E = ResidueClassRingElement;

  def one: E = new ResidueClassRingElement(baseRing.one);

  class ResidueClassRingElement (e : baseRing.E)
  {
    def representative: baseRing.E = e % modulus;

    def +(b: E) = new ResidueClassRingElement(
      this.representative + b.representative); 
  }
}


object DependentTypeTest extends Application
{
  val two = new Integers.Integer(2);
  val mod2ring = new ResidueClassRing(Integers, two);

  println(mod2ring.one + mod2ring.one);
}
هل كانت مفيدة؟

المحلول

يبدو أن هذا يعمل ، لكنني لم أستطع التخلص من الممثلين عند حساب الممثل:

package dependenttypetest

abstract class EuclideanRing{
  thisRing =>
  type E <: EuclideanRingElement;
  def one: E;
  trait EuclideanRingElement
  {
    def ring = thisRing;

    def +(b: E): E;
    def %(b: E): E;
  }
}

class Integers extends EuclideanRing {
  type E = Integer;
  val one: Integer = new Integer(1);
  class Integer(n: Int) extends EuclideanRingElement
  {
    val intValue: Int = n;
    def +(b: Integer): Integer = new Integer(intValue + b.intValue);
    def %(b: Integer): Integer = new Integer(intValue % b.intValue);
    override def toString = "Int" + intValue
  }
}

object Integers extends Integers 

class ResidueClassRing[ER <: EuclideanRing] (modulus : ER#E) {
  val baseRing = modulus.ring
  type E = ResidueClassRingElement;
  def one: E = new ResidueClassRingElement(baseRing.one);

  class ResidueClassRingElement (e : baseRing.E)
  {
    def representative = e % modulus.asInstanceOf[baseRing.E];
    def +(b: E) = new ResidueClassRingElement(
      this.representative + b.representative);
    override def toString = "RC(" + representative + ")"
  }
}

object DependentTypeTest extends Application {
  val two =  new Integers.Integer(2);
  val mod2ring = new ResidueClassRing[Integers](two)

  println(mod2ring.one + mod2ring.one)
}

راجع للشغل: كن حذرًا مع سمة التطبيق ، يتم إهمالها بحق.

نصائح أخرى

تحديث: وأضاف IntRing لتوضيح التغييرات في trait Ring

يبدو أن المشكلة هي أن نوع الاستدلال لا يختار تلقائيًا النوع الأكثر تحديداً وهو ما تحتاجه في حالتك. بالإضافة إلى ذلك ، لا يمكن أن يكون لديك وسيطة من النوع التابع في نفس قائمة المعلمات مثل النوع المحدد.

ما يمكنك القيام به هو سحب المثيل الذي يعتمد عليه النوع في النطاق الخارجي (الذي يتم في Rings الطبقة) وإجبار المترجم على اختيار النوع الأكثر تحديداً عند إنشاء إنشاء Rings صف دراسي:

trait Ring {

  type Element <: EuclideanRingElement

  def one: Element

  // for convenience could be defined anywhere of course
  lazy val rings: Rings[this.type] = new Rings[this.type](this)

  trait EuclideanRingElement {
    def +(e: Element): Element
    def %(e: Element): Element
  }
}

class Rings[R <: Ring](val base: R) {

  class ResidueClassRing(m: base.Element) {

    def one = new Element(base.one)

    class Element(e: base.Element) {
      def repr = e % m
      def +(that: Element) = new Element(this.repr + that.repr)
    }
  }
}

object IntRing extends Ring {

val one = new Element(1)

  class Element(val n: Int) extends EuclideanRingElement {
    def +(that: Element) = new Element(this.n + that.n)
    def %(that: Element) = new Element(this.n % that.n)
    override def toString = n formatted "Int(%d)"
  }
}

الآن يمكنك استخدامه مثل هذا:

scala> import IntRing._
import IntRing._

scala> val two = new Element(2)
two: IntRing.Element = Int(2)


scala> val r2 = new rings.ResidueClassRing(two)
r2: IntRing.rings.ResidueClassRing = Rings$ResidueClassRing@4b5075f9
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top