Scala 中的类型级模式匹配
type level pattern matching in scala
理想情况下,我想在 Scala 的类型级别上编写 Haskell 样式模式匹配,如下所示:
shapeless 可以用于这样的事情吗?
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
那么它 returns String
如果它需要 Boolean
那么它 returns Int
.
澄清(基于)
下面是我想在函数和类型类中使用这些类型的方式:
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
}
}
您使用带有类型成员的类型类样式隐式结构。
// 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] }
这里有两个非无形解。
一些类型级别 table 的具有有趣名称的常量:
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
.
这样的东西
您可以将要为其定义 F
的每个类型 T
提升为同时具有 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
进行抽象)
在 "Clarification" 下的代码中,您缺少绑定到类型成员 F
:
的 F <: WrappedF
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
}
}
理想情况下,我想在 Scala 的类型级别上编写 Haskell 样式模式匹配,如下所示:
shapeless 可以用于这样的事情吗?
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
那么它 returns String
如果它需要 Boolean
那么它 returns Int
.
澄清(基于
下面是我想在函数和类型类中使用这些类型的方式:
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
}
}
您使用带有类型成员的类型类样式隐式结构。
// 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] }
这里有两个非无形解。
一些类型级别 table 的具有有趣名称的常量:
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
. 这样的东西
您可以将要为其定义
F
的每个类型T
提升为同时具有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
进行抽象)
在 "Clarification" 下的代码中,您缺少绑定到类型成员 F
:
F <: WrappedF
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
}
}