理想情况下,我想在Scala中的类型级别编写Haskell样式模式匹配,如下所示:
可以无形地用于这样的事情吗?
object Test{
type F[Int] = String
type F[Boolean] = Int // but this line does not compile
implicitly[String =:= F[Int]]
implicitly[Int =:= F[Boolean]]
}
在此示例中,如果F
获取Int
,则会返回String
,如果需要Boolean
,则返回Int
。
澄清(基于this answer)
以下是我希望在函数和类型类中使用这些类型的方法:
abstract class WrappedF[T] {
type F
type Unwrap = T
}
type F[X <: WrappedF[_]] = X#F
class IntF extends WrappedF[Int] { type F = StringF }
class BooleanF extends WrappedF[Boolean] { type F = IntF }
class StringF extends WrappedF[String] { type F = Nothing }
implicitly[String =:= F[IntF]#Unwrap]
implicitly[Int =:= F[BooleanF]#Unwrap]
implicitly[String =:= F[F[BooleanF]]#Unwrap]
// this is a type class definition where `V` is a member of the `Test` class
// `f`'s type should be defined by `V`, but it does not work :(
trait Test[V <: WrappedF[V]]{
def f(a: F[V]#Unwrap): F[V]#Unwrap // this does not compile
}
implicit object TestImpl extends Test[IntF]{
override def f(a: F[IntF]#Unwrap): F[IntF]#Unwrap = {
val z: F[IntF]#Unwrap = "fd"+a
z
}
}
答案 0 :(得分:7)
这里有两个非无形的解决方案。
一个带有趣名字的小型常量表:
type F = {
type Int = java.lang.String
type Boolean = scala.Int
}
implicitly[String =:= F#Int]
implicitly[Int =:= F#Boolean]
此处,F
是一个类型,其中有两个类型成员,其名称为Int
和Boolean
(可能是I
和B
,这两个常量都不是与任何方式都与Int
或Boolean
真正联系在一起。这不构成:你不能写下像F#F#Int
。
您可以将要定义T
的每个类型F
提升为同时包含T
和F[T]
类型的类型:
abstract class WrappedF[T] {
type F
type Unwrap = T
}
type F[X <: WrappedF[_]] = X#F
class IntF extends WrappedF[Int] { type F = StringF }
class BooleanF extends WrappedF[Boolean] { type F = IntF }
class StringF extends WrappedF[String] { type F = Nothing }
implicitly[String =:= F[IntF]#Unwrap]
implicitly[Int =:= F[BooleanF]#Unwrap]
implicitly[String =:= F[F[BooleanF]]#Unwrap]
由于...F
和#Unwrap
,这会增加更多噪音,但纯粹是一种类型级别的计算,并且它组成(如最后一个示例所示)。
更新(更适合抽象V <: WrappedF
)
在“澄清”下的代码中,您错过了F <: WrappedF
类型成员F
上的约束:
abstract class WrappedF {
type F <: WrappedF
type Unwrap
}
type F[X <: WrappedF] = X#F
class IntF extends WrappedF { type Unwrap = Int; type F = StringF }
class BooleanF extends WrappedF { type Unwrap = Boolean; type F = IntF }
class StringF extends WrappedF { type Unwrap = String; type F = Nothing }
implicitly[String =:= F[IntF]#Unwrap]
implicitly[Int =:= F[BooleanF]#Unwrap]
implicitly[String =:= F[F[BooleanF]]#Unwrap]
trait Test[V <: WrappedF]{
def f(a: F[V]#Unwrap): F[V]#Unwrap // this does not compile
}
implicit object TestImpl extends Test[IntF] {
override def f(a: String): String = {
val z: F[IntF]#Unwrap = "fd" + a
z
}
}
答案 1 :(得分:5)
您使用带有类型成员的类型类型样式隐式结构。
// sealed for closed family
class F[I] { type O }
object F {
type Rel[I, O0] = F[I] { type O = O0 }
/* private */ def mkF[I, O0]: Rel[I, O0] = new F[I] { override type O = O0 }
implicit val fInt: Rel[Int, String] = mkF
implicit val fBoolean: Rel[Boolean, Int] = mkF
def apply[I](implicit f: F[I]): f.type = f // f.type survives the refinement (see what breaks on removal)
}
locally { val temp = F[Int]; implicitly[temp.O =:= String] }
locally { val temp = F[Boolean]; implicitly[temp.O =:= Int] }
locally { val temp0 = F[Boolean]; val temp1 = F[temp0.O]; implicitly[temp1.O =:= String] }