我正在尝试为String创建一个scalaz的String类型的实例。到目前为止,这就是我所得到的:
implicit val stringIsEmpty = new IsEmpty[({ type t[+A] = String })#t] {
def isEmpty[A](fa: String) = ???
def empty[A] = ???
def plus[A](a: String, b: => String) = ???
}
def f[F[_]: IsEmpty, A](fa: F[A]): F[A] = fa现在,String是类*,而IsEmpty[F]期望F是类* -> *,因此类型为lambda f[+A] = String。
这是可行的,但只有当字符串被键入为t时才能工作,即:
// doesn't compile
f("hello")
// compiles if I extract `t` into a type alias and annotate the string with it
type t[+A] = String
implicit val stringIsEmpty = new IsEmpty[t] { /** **/ }
f("hello": t[Nothing])是否有任何方法来实现IsEmpty,使我能够将f应用于一个正常的字符串?
发布于 2016-03-17 19:59:13
事实证明,您可以使用Unapply魔术将一种类型的*转换成一种类型的* -> *。
这是我的解决方案:
def f[F[_]: IsEmpty, A](fa: F[A]): F[A] = fa
def fU[FA](fa: FA)(implicit U: Unapply[IsEmpty, FA]) =
f[U.M, U.A](U(fa))(U.TC)现在你可以直接做fU("hello")了。返回类型也将被正确地推断为String。
据我所知,您确实需要这个辅助函数,这有点痛苦,但我想这就是缺少直接编译器支持。所要付出的代价
当我意识到Applicative有一个用于String的实例,并且您可以做"hello".replicateM(3)之类的事情时,我就有了这个想法。
我把这句话具体化如下:
scala> import scala.reflect.runtime.universe
import scala.reflect.runtime.universe
scala> universe.reify("hello".replicateM(3)).tree
res32: reflect.runtime.universe.Tree = Scalaz.ToApplicativeOpsUnapply("hello")(Unapply.unapplyA(Applicative.monoidApplicat
ive(Scalaz.stringInstance))).replicateM(3)ToApplicativeOpsUnapply在幕后透露了这个秘密:
implicit def ToApplicativeOpsUnapply[FA](v: FA)(implicit F0: Unapply[Applicative, FA]) =
new ApplicativeOps[F0.M,F0.A](F0(v))(F0.TC)https://stackoverflow.com/questions/36060690
复制相似问题