3

scalaz.IsEmptyタイプクラスインスタンスを持つものをすべてラップするジェネリックメソッドを作成しようとしていますOption。空の値を返しNone、空でない場合はラップしSomeます。これが私がこれまでに思いついたものです:

import scalaz._
import Scalaz._

def asOption0[C](c: C)(implicit ev: IsEmpty[({ type B[A] = C })#B]) =
  if (ev.isEmpty(c)) None else Some(c)

def asOption1[A, C[_]](c: C[A])(implicit ev: IsEmpty[C]) =
  if (ev.isEmpty(c)) None else Some(c)

asOption0のようなプリミティブ型で機能しStringラムダ型Cを使用してその形状を示すB[_])、次asOption1のような単項型コンストラクターを持つ型で機能しますList

scala> asOption0("")
res1: Option[String] = None

scala> asOption1(List(1,2,3))
res0: Option[List[Int]] = Some(List(1, 2, 3))

scala> asOption0(List(1,2,3))
<console>:17: error: could not find implicit value for parameter
                     ev: scalaz.IsEmpty[[A]List[Int]]

scala> asOption1("hello")
<console>:17: error: could not find implicit value for parameter
                     ev: scalaz.IsEmpty[Comparable]

String、、、Listおよびより高い種類のタイプに対して同時に機能する1つのメソッドを作成することは可能ですか?

4

2 に答える 2

4
scala> asOption0(List(1,2,3))
<console>:17: error: could not find implicit value for parameter
                     ev: scalaz.IsEmpty[[A]List[Int]]

このエラーは、リストのインスタンスが見つからないことを示していますIsEmpty。これは、型パラメーターが重要でないためです。Scalaz は、型パラメーターに関係なく、すべてのリストに対して暗黙的です。

メソッドは をリクエストしIsEmpty[List[Int]]、Scalaz は に対して利用できるものしか持っていませんIsEmpty[List[_]]IsEmptyは list の内容を気にしないのでasOption0、より詳細なバージョンの を提供することでメソッドを満足させるだけですIsEmpty:

def asOption0[C](c: C)(implicit ev: IsEmpty[({ type B[_] = C })#B]) =
  if (ev.isEmpty(c)) None else Some(c)  

implicit def detailedIsEmpty[A, C[_]](implicit ev: IsEmpty[C]) =
  ev.asInstanceOf[IsEmpty[({ type B[_] = C[A] })#B]]


asOption0("test")             //> res0: Option[String] = Some(test)
asOption0(List(1, 2, 3))      //> res1: Option[List[Int]] = Some(List(1, 2, 3))
asOption0("")                 //> res2: Option[String] = None
asOption0(List[Int]())        //> res3: Option[List[Int]] = None

編集

問題をもう一度見て、少しきれいな解決策を見つけました。OPが探している結果ではないのではないかと心配しています。

trait IsEmptyLike[F] {
  def isEmpty(fa: F): Boolean
}

object IsEmptyLike {

  implicit def case0[A](implicit ev: IsEmpty[({ type B[_] = A })#B]) =
    new IsEmptyLike[A] {
      def isEmpty(fa: A): Boolean = ev.isEmpty(fa)
    }
  implicit def case1[A[_], B](implicit ev: IsEmpty[A]) =
    new IsEmptyLike[A[B]] {
      def isEmpty(fa: A[B]): Boolean = ev.isEmpty(fa)
    }
  implicit def case2[A[_, _], B, C](implicit ev: IsEmpty[({ type D[X] = A[B, X] })#D]) =
    new IsEmptyLike[A[B, C]] {
      def isEmpty(fa: A[B, C]): Boolean = ev.isEmpty(fa)
    }
}

def asOption[C](c: C)(implicit ev: IsEmptyLike[C]) =
  if (ev.isEmpty(c)) None else Some(c)
于 2013-02-17T22:03:01.477 に答える
2

の助けを借りて、多くの異なる型 ( でサポートされているもの) に対して機能し、追加の暗黙的な変換を必要としないscalaz.Unapplyジェネリックを作成できます。asOptionUnapply

import scalaz._
import Scalaz._

def asOption[MA](ma: MA)(implicit U: Unapply[IsEmpty, MA]): Option[MA] =
  if (U.TC.isEmpty(U(ma))) None else Some(ma)

asOption("")              //> res0: Option[String] = None
asOption("hello")         //> res1: Option[String] = Some(hello)

asOption(List[Int]())     //> res2: Option[List[Int]] = None
asOption(List(1,2))       //> res3: Option[List[Int]] = Some(List(1, 2))

asOption(Map[Int,Int]())  //> res4: Option[Map[Int,Int]] = None
asOption(Map(1 -> 2))     //> res5: Option[Map[Int,Int]] = Some(Map(1 -> 2))

Unapplyの docstring の最初の部分は次のとおりです。

typeに 適用されるMA型コンストラクターとして分解された型を、対応する型クラス instance と共に表します。M[_]ATC[M]

コンパニオン オブジェクトの暗黙的な変換は、 SI-2712で説明されているコンパイラの直接サポートの代わりに、部分的に適用された型コンストラクタの型クラス インスタンスを取得する手段を提供します。

于 2013-02-20T18:30:39.007 に答える