如何为泛型类型编写scalaz.IsEmpty参数
我正在尝试编写一个通用方法,将任何具有typeclass实例的对象包装到如何为泛型类型编写scalaz.IsEmpty参数,scala,generics,typeclass,scalaz,higher-kinded-types,Scala,Generics,Typeclass,Scalaz,Higher Kinded Types,我正在尝试编写一个通用方法,将任何具有typeclass实例的对象包装到选项中。对于空值,它应该返回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
选项中。对于空值,它应该返回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
(使用a表示C
具有B[\u]
)的形状,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]
scala>asOption0(“”)
res1:选项[字符串]=无
scala>asOption1(列表(1,2,3))
res0:Option[List[Int]=Some(List(1,2,3))
scala>asOption0(列表(1,2,3))
:17:错误:找不到参数的隐式值
ev:scalaz.IsEmpty[[A]List[Int]]
scala>A选项1(“你好”)
:17:错误:找不到参数的隐式值
ev:scalaz.IsEmpty[可比]
是否可以编写一个同时适用于字符串
、列表
和更高类型的方法
scala> asOption0(List(1,2,3))
<console>:17: error: could not find implicit value for parameter
ev: scalaz.IsEmpty[[A]List[Int]]
编辑
我又看了一眼这个问题,找到了一个看起来更干净的解决方案。我担心这不是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)
在的帮助下,可以编写一个通用的a选项
,该选项适用于许多不同的类型(那些由Unapply
支持的类型),并且不需要任何额外的隐式转换:
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))
以下是的docstring的第一部分:
表示已作为类型构造函数分解为的类型MA
应用于类型A
,以及相应的类型类实例TC[M]
伴随对象中的隐式转换提供了获取类型类的方法
部分应用类型构造函数的实例,代替直接编译器支持
如中所述
隐式参数的隐式转换。。。有趣!我从来没见过。如果asOption0
也适用于例如Map
,则似乎需要进行另一个转换:但这提出了一个问题:为什么Scalaz为Map提供了一个IsEmpty[({type F[V]=Map[K,V]})的实例
而不是IsEmpty[({type F[[u]=Map[K,V]})F]})
。我看到您更改了您的问题。你能解释一下你到底想要实现什么吗?@EECOLOR我更改了标题,以便更好地匹配我问题的最后一句话。我希望有一个适用于任何类型的解决方案,不仅适用于*
和*->*
。另一个“显式”隐式转换似乎对于例如Map
是必要的,这是不令人满意的。我确实觉得只要提供适当的typeclass实例就足以使用a选项
。对不起,前面的标题有误导性!我编辑了我的答案以添加另一个解决方案。然而,这可能仍然不是你想要的。如果不是,你能解释一下你在找什么吗?@EECOLOR似乎我通过使用scalaz.Unapply
找到了我问题的一个答案。此解决方案不需要任何额外的隐式转换,只需要IsEmpty
的一个实例。
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))