类型 * 类型的类型类实例,其中需要类型 * -> *
Instance of typeclass for types of kind * where a type of kind * -> * is expected
我正在尝试为 String
创建 scalaz 的 IsEmpty
类型类的实例。这是我到目前为止所得到的:
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
应用于字符串?
事实证明,您可以使用 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")
。 return 类型也将被正确推断为 String
.
据我所知,你确实需要这个辅助功能,这有点痛苦,但我想这就是缺少 direct compiler support.
的代价
当我意识到 String
有一个 Applicative
的实例并且你可以做类似 "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)
我正在尝试为 String
创建 scalaz 的 IsEmpty
类型类的实例。这是我到目前为止所得到的:
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
应用于字符串?
事实证明,您可以使用 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")
。 return 类型也将被正确推断为 String
.
据我所知,你确实需要这个辅助功能,这有点痛苦,但我想这就是缺少 direct compiler support.
的代价当我意识到 String
有一个 Applicative
的实例并且你可以做类似 "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)