ম্যাক্রো থেকে বেনাম শ্রেণীর পদ্ধতিগুলির সাথে একটি কাঠামোগত ধরণ প্রাপ্ত


181

ধরা যাক আমরা এমন ম্যাক্রো লিখতে চাই যা কিছু ধরণের সদস্য বা পদ্ধতির সাথে একটি বেনাম শ্রেণীর সংজ্ঞা দেয় এবং তারপরে সেই শ্রেণীর একটি উদাহরণ তৈরি করে যা স্টাট্যালি স্ট্রাকচারাল ধরণের হিসাবে methods পদ্ধতিগুলির সাথে টাইপ করা হয়, ইত্যাদি। এটি ম্যাক্রো সিস্টেমের মাধ্যমে 2.10 সালে সম্ভব। 0, এবং টাইপ সদস্য অংশটি অত্যন্ত সহজ:

object MacroExample extends ReflectionUtils {
  import scala.language.experimental.macros
  import scala.reflect.macros.Context

  def foo(name: String): Any = macro foo_impl
  def foo_impl(c: Context)(name: c.Expr[String]) = {
    import c.universe._

    val Literal(Constant(lit: String)) = name.tree
    val anon = newTypeName(c.fresh)

    c.Expr(Block(
      ClassDef(
        Modifiers(Flag.FINAL), anon, Nil, Template(
          Nil, emptyValDef, List(
            constructor(c.universe),
            TypeDef(Modifiers(), newTypeName(lit), Nil, TypeTree(typeOf[Int]))
          )
        )
      ),
      Apply(Select(New(Ident(anon)), nme.CONSTRUCTOR), Nil)
    ))
  }
}

( ReflectionUtilsএমন কোনও সুবিধা বৈশিষ্ট্য যেখানে আমার constructorপদ্ধতি সরবরাহ করে))

এই ম্যাক্রো আমাদের বেনাম শ্রেণীর টাইপ সদস্যের নামটি স্ট্রিং আক্ষরিক হিসাবে নির্দিষ্ট করতে দেয়:

scala> MacroExample.foo("T")
res0: AnyRef{type T = Int} = $1$$1@7da533f6

মনে রাখবেন এটি যথাযথভাবে টাইপ করা হয়েছে। আমরা নিশ্চিত করতে পারি যে প্রত্যাশা অনুযায়ী সবকিছুই কাজ করছে:

scala> implicitly[res0.T =:= Int]
res1: =:=[res0.T,Int] = <function1>

এখন ধরা যাক আমরা একটি পদ্ধতি দিয়ে একই জিনিসটি করার চেষ্টা করি:

def bar(name: String): Any = macro bar_impl
def bar_impl(c: Context)(name: c.Expr[String]) = {
  import c.universe._

  val Literal(Constant(lit: String)) = name.tree
  val anon = newTypeName(c.fresh)

  c.Expr(Block(
    ClassDef(
      Modifiers(Flag.FINAL), anon, Nil, Template(
        Nil, emptyValDef, List(
          constructor(c.universe),
          DefDef(
            Modifiers(), newTermName(lit), Nil, Nil, TypeTree(),
            c.literal(42).tree
          )
        )
      )
    ),
    Apply(Select(New(Ident(anon)), nme.CONSTRUCTOR), Nil)
  ))
}

তবে আমরা যখন এটি চেষ্টা করে দেখি তখন আমরা কোনও কাঠামোগত প্রকারটি পাই না:

scala> MacroExample.bar("test")
res1: AnyRef = $1$$1@da12492

তবে আমরা যদি সেখানে কোনও অতিরিক্ত বেনাম শ্রেণি আটকে থাকি:

def baz(name: String): Any = macro baz_impl
def baz_impl(c: Context)(name: c.Expr[String]) = {
  import c.universe._

  val Literal(Constant(lit: String)) = name.tree
  val anon = newTypeName(c.fresh)
  val wrapper = newTypeName(c.fresh)

  c.Expr(Block(
    ClassDef(
      Modifiers(), anon, Nil, Template(
        Nil, emptyValDef, List(
          constructor(c.universe),
          DefDef(
            Modifiers(), newTermName(lit), Nil, Nil, TypeTree(),
            c.literal(42).tree
          )
        )
      )
    ),
    ClassDef(
      Modifiers(Flag.FINAL), wrapper, Nil,
      Template(Ident(anon) :: Nil, emptyValDef, constructor(c.universe) :: Nil)
    ),
    Apply(Select(New(Ident(wrapper)), nme.CONSTRUCTOR), Nil)
  ))
}

এটি কাজ করে:

scala> MacroExample.baz("test")
res0: AnyRef{def test: Int} = $2$$1@6663f834

scala> res0.test
res1: Int = 42

এই অত্যন্ত কুশলী-আপনার ভালো জিনিস করতে দেয় কি এই জন্য, যেমন-কিন্তু আমি বুঝতে পারছি না কেন এটা কাজ করে, এবং ধরন সদস্য সংস্করণ কাজ, কিন্তু না bar। আমি জানি এটি সংজ্ঞায়িত আচরণ নয় , তবে এটি কোনও অর্থবোধ করে? কোনও ম্যাক্রো থেকে কাঠামোগত ধরণের (এটির পদ্ধতিগুলি সহ) পাওয়ার কী ক্লিনার উপায় আছে?


14
আকর্ষণীয়ভাবে যথেষ্ট, আপনি যদি ম্যাক্রোতে উত্পাদন করার পরিবর্তে আরপিএলে একই কোডটি লিখেন তবে এটি কাজ করে: স্কেল> {চূড়ান্ত শ্রেণির আনন {Def x = 2}; নতুন আনন} রেজি 1: যেকোনও রেফ {ডিফ এক্স: ইনট} = আনোন $ 1 @ 5295c398। প্রতিবেদনের জন্য ধন্যবাদ! আমি এই সপ্তাহে একবার দেখুন।
ইউজিন বার্মাকো

1
মনে রাখবেন যে আমি এখানে একটি সমস্যা দায়ের করেছি ।
ট্র্যাভিস ব্রাউন

না, কোনও ব্লকার নয়, ধন্যবাদ - অতিরিক্ত বেনাম শ্রেণীর কৌশল যখনই আমার প্রয়োজন হবে আমার জন্য কাজ করেছে। আমি এই প্রশ্নের উপর কয়েকটি উত্সাহ লক্ষ্য করেছি এবং স্থিতি সম্পর্কে আগ্রহী ছিলাম।
ট্র্যাভিস ব্রাউন

3
টাইপ সদস্য অংশ অত্যন্ত সহজ -> ডাব্লুটিএফ? আপনি অত্যন্ত ক্র্যাক! অবশ্যই ভাল পথে :)
ZaoTaoBao

3
এখানে 153 টি upvotes রয়েছে এবং স্কালা-অং.এল.গ্রেজে ইস্যুটির জন্য কেবল 1 টি রয়েছে । আরও আপগেটগুলি কী দ্রুত সমাধান করতে পারে?
মুডবুম

উত্তর:


9

এই প্রশ্নের ট্র্যাভিস এখানে নকল করে উত্তর দিয়েছেন । ট্র্যাকারে এবং ইউজিনের আলোচনার (মন্তব্য এবং মেলিং তালিকায়) ইস্যুটির লিঙ্ক রয়েছে।

প্রকার চেকারের বিখ্যাত "স্কাইল্লা এবং চারিবিডিস" বিভাগে, আমাদের নায়ক সিদ্ধান্ত নেয় যে অন্ধকার নাম বর্জন করবেন এবং কাঠামোগত ধরণের সদস্য হিসাবে আলোটি দেখবেন।

টাইপ চেকারকে ট্রিক করার বেশ কয়েকটি উপায় রয়েছে (যা ওডিসিয়াসের মেষকে জড়িয়ে ধরার চালায় না)। সবচেয়ে সহজ হ'ল একটি ডামি স্টেটমেন্টটি সন্নিবেশ করানো যাতে ব্লকটি কোনও বেনাম শ্রেণীর মতো না লাগে যার পরে এটি ইনস্ট্যান্টেশন হয়।

যদি টাইপের বিজ্ঞপ্তি দেয় যে আপনি একটি সর্বজনীন শব্দ যা বাইরের দ্বারা রেফারেন্স করা হয় না, এটি আপনাকে ব্যক্তিগত করে তুলবে।

object Mac {
  import scala.language.experimental.macros
  import scala.reflect.macros.Context

  /* Make an instance of a structural type with the named member. */
  def bar(name: String): Any = macro bar_impl

  def bar_impl(c: Context)(name: c.Expr[String]) = {
    import c.universe._
    val anon = TypeName(c.freshName)
    // next week, val q"${s: String}" = name.tree
    val Literal(Constant(s: String)) = name.tree
    val A    = TermName(s)
    val dmmy = TermName(c.freshName)
    val tree = q"""
      class $anon {
        def $A(i: Int): Int = 2 * i
      }
      val $dmmy = 0
      new $anon
    """
      // other ploys
      //(new $anon).asInstanceOf[{ def $A(i: Int): Int }]
      // reference the member
      //val res = new $anon
      //val $dmmy = res.$A _
      //res
      // the canonical ploy
      //new $anon { }  // braces required
    c.Expr(tree)
  }
}

2
আমি কেবলমাত্র নোট করব যে আমি নিজেই এই প্রশ্নের মধ্যে প্রথম কাজটি সরবরাহ করেছি (এটি কেবল এখানে বিশিষ্ট নয়)। এই উত্তরটি প্রশ্নটি গুটিয়ে দেওয়ার জন্য আমি খুশি — আমি মনে করি আমি বাগটি ঠিক করার জন্য অস্পষ্টভাবে অপেক্ষা করছিলাম।
ট্র্যাভিস ব্রাউন 11

@ ট্র্যাভিস ব্রাউন আমি বাজি ধরছি আপনার ব্যাট বেল্টেও অন্যান্য সরঞ্জাম রয়েছে। মাথার জন্য থিক্স আপ: আমি ধরে নিয়েছি আপনার এএসটি "পুরানো অতিরিক্ত ধনুর্বন্ধনী কৌশল", তবে আমি এখন দেখছি যে ক্লাসডেফ / প্রয়োগটি তাদের নিজস্ব ব্লকে মোড়ানো নয়, যেমন হয় new $anon {}। আমার অন্যান্য গ্রহণযোগ্যতা হ'ল ভবিষ্যতে আমি anonম্যাক্রোগুলিতে কোয়াসিকোটস বা অনুরূপ বিশেষ নাম ব্যবহার করব না ।
সোম-স্নিট

q "$ {s: স্ট্রিং}" সিনট্যাক্সটি কিছুটা বিলম্বিত হয়, বিশেষত যদি আপনি স্বর্গ ব্যবহার করছেন। পরের সপ্তাহের চেয়ে পরের মাসের মতো আরও বেশি।
শাবলিন

@ সোম-স্নিটিট @ ড্যানি-শাবালিন, কাঠামোগত ধরণের এ-লা জন্য কোনও বিশেষ ধরণের কৌশল আছে shapeless.Generic? Auxপ্যাটার্ন রিটার্ন টাইপগুলিকে বাধ্য করার জন্য আমার সর্বোত্তম উদ্দেশ্য সত্ত্বেও সংকলক স্ট্রাকচারাল ধরণের মাধ্যমে দেখতে অস্বীকার করে।
ফ্লাভিয়ান
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.