1

私は次の特性を持っています (ランク 2 ポリモーフィズムクリックのようなものを取得するには)

type Id[A] = A
trait ~>[F[_], G[_]] {
def apply[A](a: F[A]): G[A]
def isDefinedAt[A](a: A): Boolean}

そして、部分関数をこの特性に変換する関数:

implicit def pft[B: ClassTag](f: PartialFunction[B, B])= new (Id ~> Id) {
def apply[A](a: A): A = f(a.asInstanceOf[B]).asInstanceOf[A]
def isDefinedAt[A: ClassTag](a: A)(implicit ev2: ClassTag[A]) : Boolean = /*type check*/
               f.isDefinedAt(a.asInstanceOf[B]) }

だから私の問題は isDefinedAt メソッドです。実行時に A が B のインスタンスであるかどうかを確認する必要があります。a.isInstanceOf[B] は型消去のため機能しません。

TypeTag/ClassTag を使用しようとしましたが、B には問題なく動作しますが、A のタイプは常に Any ではありません。

では、A が B のインスタンスであるかどうかを確認するにはどうすればよいでしょうか。

更新:私はこのコードでそれを使用します:

  def map[A](f: Id ~> Id, x: A): A =
    {
      val y = x match {
        //many matches more on my own data structures
        case l : List[_] => l.map(map(f,_))
        case m : Map[_,_] => m.map(map(f,_))
        case (a,b) => (map(f,a),map(f,b))
        case a => a
      }
      if (f.isDefinedAt(y))
        f(y).asInstanceOf[A]
      else
        y.asInstanceOf[A]
    }

~> を直接使用すると、typeTag[A].tpe <:< typeTag[B].tpe ですべて正常に動作します。

しかし、この map 関数で使用すると、typeTag[A].tpe は常に Any になります。

4

1 に答える 1

1

isDefinedAt の署名を変更して TypeTag を取得しても問題ない場合は、次の方法で pft を実装できます。

  type Id[A] = A
  trait ~>[F[_], G[_]] {
    def apply[A](a: F[A]): G[A]
    def isDefinedAt[A: TypeTag](a: A): Boolean
  }

  implicit def pft[B: TypeTag](f: PartialFunction[B, B]) = new (Id ~> Id) {
    def apply[A](a: A): A = f(a.asInstanceOf[B]).asInstanceOf[A]
    def isDefinedAt[A: TypeTag](a: A): Boolean =
      typeTag[A].tpe =:= typeTag[B].tpe && f.isDefinedAt(a.asInstanceOf[B])
  }

このソリューションは、 と の両方のTypeTagを取得し、部分関数のメソッドに委譲する前に、それらが同じ型であることを確認します。タイプ タグの詳細については、この回答を参照してください。BAisDefinedAt

例えば:

val halfEven: PartialFunction[Int, Int] = {
  case n if n % 2 == 0 => n / 2
}

val halfEvenT: Id ~> Id = halfEven

halfEvenT.isDefinedAt(1) // false
halfEvenT.isDefinedAt(2) // true
halfEvenT.isDefinedAt("test") // false

より一般的には、制約された部分変換を、制約する追加の上位の種類の型を取るように定義できますA

  trait ConstrainedPartialTransformation[F[_], G[_], C[_]] {
    def apply[A: C](a: F[A]): G[A]
    def isDefinedAt[A: C](a: A): Boolean
  }

  implicit def cpft[B: TypeTag](f: PartialFunction[B, B]) = new ConstrainedPartialTransformation[Id, Id, TypeTag] {
    def apply[A: TypeTag](a: A) = f(a.asInstanceOf[B]).asInstanceOf[A]
    def isDefinedAt[A: TypeTag](a: A) =
      typeTag[A].tpe =:= typeTag[B].tpe && f.isDefinedAt(a.asInstanceOf[B])
  }

これは、Scalaz 7 が A にバインドされたコンテキストがある自然変換をサポートする方法に似ています。Scalaz 7 のConstrainedNaturalTransformationを参照してください。

于 2013-03-16T18:18:12.703 に答える