Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/typo3/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Scala “如何定义”;类型析取“;(联合类型)?_Scala - Fatal编程技术网

Scala “如何定义”;类型析取“;(联合类型)?

Scala “如何定义”;类型析取“;(联合类型)?,scala,Scala,必须处理重载方法的双重定义的一种方法是用模式匹配替换重载: object Bar { def foo(xs: Any*) = xs foreach { case _:String => println("str") case _:Int => println("int") case _ => throw new UglyRuntimeException() } } 这种方法要求我们放弃对foo参数的静态类型检查。如果能写作就更

必须处理重载方法的双重定义的一种方法是用模式匹配替换重载:

object Bar {
   def foo(xs: Any*) = xs foreach { 
      case _:String => println("str")
      case _:Int => println("int")
      case _ => throw new UglyRuntimeException()
   }
}
这种方法要求我们放弃对
foo
参数的静态类型检查。如果能写作就更好了

object Bar {
   def foo(xs: (String or Int)*) = xs foreach {
      case _: String => println("str")
      case _: Int => println("int")
   }
}
我可以用
接近它,但有两种以上的类型会让它变得很丑:

type or[L,R] = Either[L,R]

implicit def l2Or[L,R](l: L): L or R = Left(l)
implicit def r2Or[L,R](r: R): L or R = Right(r)

object Bar {
   def foo(xs: (String or Int)*) = xs foreach {
      case Left(l) => println("str")
      case Right(r) => println("int")
   }
}

看起来,一个通用(优雅、高效)的解决方案需要定义
Either3
Either4
。。。。有人知道实现同样目的的替代解决方案吗?据我所知,Scala没有内置的“类型析取”。此外,上面定义的隐式转换是否隐藏在标准库的某个地方,以便我可以直接导入它们?

好吧,这很聪明,但我很确定您已经知道,您的主要问题的答案是各种各样的“否”。Scala以不同的方式处理重载,必须承认,它没有您描述的那么优雅。有些是因为Java的互操作性,有些是因为不想触及类型推断算法的边缘情况,有些是因为它根本不是Haskell

你可以看看,它有一个叫做。我的印象是,这对
match
语句不起作用,但可以使用高阶函数模拟匹配。例如,请看一看,但是请注意,“模拟匹配”部分被注释掉了,可能是因为它还没有完全起作用


现在让我们来看一些社论:我认为,正如你所描述的,定义它们3、4等并没有什么惊人之处。这本质上是Scala内置的标准22元组类型的双重。如果Scala有内置的析取类型,也许还有一些很好的语法,比如
{x,y,z}

那当然好了,在
Any*
的特定情况下,下面的技巧不会起作用,因为它不会接受混合类型。然而,由于混合类型也不能用于重载,这可能是您想要的

首先,用您希望接受的类型声明一个类,如下所示:

class StringOrInt[T]
object StringOrInt {
  implicit object IntWitness extends StringOrInt[Int]
  implicit object StringWitness extends StringOrInt[String]
}
接下来,像这样声明
foo

object Bar {
  def foo[T: StringOrInt](x: T) = x match {
    case _: String => println("str")
    case _: Int => println("int")
  }
}
就这样。您可以调用
foo(5)
foo(“abc”)
,它会工作,但尝试
foo(true)
它会失败。客户机代码可以通过创建
StringOrInt[Boolean]
来回避这一点,除非如下文所述,您将
StringOrInt
设为
密封的

它之所以能工作,是因为
T:StringOrInt
意味着有一个类型为
StringOrInt[T]
的隐式参数,而且因为Scala会查看类型的伴随对象内部,以查看是否存在隐式参数,从而使请求该类型的代码工作。

还有一个问题:


请参阅。

类型类解决方案可能是最好的解决方法,使用隐式。 这类似于Odersky/Spoon/Venners书中提到的幺半群方法:

abstract class NameOf[T] {
  def get : String
}

implicit object NameOfStr extends NameOf[String] {
  def get = "str"
}

implicit object NameOfInt extends NameOf[Int] {
 def get = "int"
}

def printNameOf[T](t:T)(implicit name : NameOf[T]) = println(name.get)

如果随后在REPL中运行此命令:

scala> printNameOf(1)
int

scala> printNameOf("sss")
str

scala> printNameOf(2.0f)
<console>:10: error: could not find implicit value for parameter nameOf: NameOf[
Float]
       printNameOf(2.0f)

              ^
scala>printNameOf(1)
int
scala>printNameOf(“sss”)
str
scala>printNameOf(2.0f)
:10:错误:找不到参数nameOf的隐式值:nameOf[
浮动]
打印名称(2.0f)
^

可以概括如下:

sealed trait Or[A, B]

object Or {
   implicit def a2Or[A,B](a: A) = new Or[A, B] {}
   implicit def b2Or[A,B](b: B) = new Or[A, B] {}
}

object Bar {
   def foo[T <% String Or Int](x: T) = x match {
     case _: String => println("str")
     case _: Int => println("int")
   }
}
def size[T : (Int |∨| String)#λ](t : T) = t match {
    case i : Int => i
    case s : String => s.length
}
trait Inv[-X]
type BOrString[X] = (Inv[B] with Inv[String]) <:< Inv[X]
def foo[X](implicit ev : BOrString[X]) = {}
或[A,B]
反对或{
隐式def a2Or[A,B](A:A)=新的或[A,B]{}
隐式def b2Or[A,B](B:B)=新的或[A,B]{}
}
对象栏{
def foo[T println(“str”)
案例:Int=>println(“Int”)
}
}
这种方法的主要缺点是

  • 正如Daniel指出的,它不处理具有混合类型的集合/变量
  • 如果匹配不完全,编译器不会发出警告
  • 如果匹配包含不可能的情况,编译器不会发出错误
  • other
    方法一样,进一步的泛化需要定义类似的
    Or3
    Or4
    等特征。当然,定义这些特征比定义相应的
    other
    类要简单得多
更新:


Mitch Blevins并展示了如何将其推广到两种以上的类型,将其称为“口吃或口吃”。

Miles Sabin在其最近的博客文章中描述了一种获得联合类型的非常好的方法:

他首先将类型的否定定义为

type ¬[A] = A => Nothing
利用德摩根定律,他可以定义工会类型

type ∨[T, U] = ¬[¬[T] with ¬[U]]
使用以下辅助构造

type ¬¬[A] = ¬[¬[A]]
type |∨|[T, U] = { type λ[X] = ¬¬[X] <:< (T ∨ U) }

这是雷克斯克尔编码联合类型的方法。简单明了

scala> def f[A](a: A)(implicit ev: (Int with String) <:< A) = a match {
     |   case i: Int => i + 1
     |   case s: String => s.length
     | }
f: [A](a: A)(implicit ev: <:<[Int with String,A])Int

scala> f(3)
res0: Int = 4

scala> f("hello")
res1: Int = 5

scala> f(9.2)
<console>:9: error: Cannot prove that Int with String <:< Double.
       f(9.2)
        ^
scala>def[A](A:A)(隐式ev:(带字符串的Int)i+1
|大小写s:String=>s.length
| }
f:[A](A:A)(隐含的ev:f(“你好”)
res1:Int=5
scala>f(9.2)

:9:错误:无法用String证明Int,我认为第一类析取类型是一个密封的超类型,具有替代子类型,并且隐式转换为所需的析取类型到这些替代子类型

我假设这解决了Miles Sabin解决方案中的-36个问题,因此可以在使用站点使用第一类类型,但我没有测试它

密封特征到字符串中
case类IntOfIntOrString(v:Int)扩展为IntOrString
case类StringOfIntOrString(v:String)扩展为rString
隐式def INTTOINTOFINTOFINTORSTRING(v:Int)=新INTOFINTOFINTORSTRING(v)
隐式def StringToStringGoFinTorString(v:String)=新StringOfIntOrString(v)
对象Int{
def unapply(t:IntOrString):选项[Int]=t匹配{
案例五:IntOfIntOrString=>Some(v.v)
案例=>无
}
}
对象字符串{
def unapply(t:IntOrString):选项[String]=t匹配{
案例五:StringOfIntOrString=>Some(v.v)
案例=>无
}
}
def大小(t:IntOrString)=t匹配{
案例Int(i)=>i
大小写字符串=>s.length
}
scala>大小(“测试”)
res0:Int=4
type ¬[A] = (() => A) => A
type ∨[T, U] = ¬[T] with ¬[U]
class D[-A](v: A) {
  def get[T](f: (() => T)) = v match {
    case x : ¬[T] => x(f)
  }
}
def size(t: D[Int ∨ String]) = t match {
  case x: D[¬[Int]] => x.get( () => 0 )
  case x: D[¬[String]] => x.get( () => "" )
  case x: D[¬[Double]] => x.get( () => 0.0 )
}
implicit def neg[A](x: A) = new D[¬[A]]( (f: (() => A)) => x )

scala> size(5)
res0: Any = 5

scala> size("")
error: type mismatch;
 found   : java.lang.String("")
 required: D[?[Int,String]]
       size("")
            ^

scala> size("hi" : D[¬[String]])
res2: Any = hi

scala> size(5.0 : D[¬[Double]])
error: type mismatch;
 found   : D[(() => Double) => Double]
 required: D[?[Int,String]]
       size(5.0 : D[?[Double]])
                ^
scala> class D[-A](v: A) {
  def get[T](f: (() => T))(implicit e: A <:< ¬[T]) = v match {
    case x : ¬[T] => x(f)
  }
}
error: contravariant type A occurs in covariant position in
       type <:<[A,(() => T) => T] of value e
         def get[T](f: (() => T))(implicit e: A <:< ?[T]) = v match {
                                           ^
type ¬[A] = A => Nothing
type ∨[T, U] = ¬[T] with ¬[U]
class Super
class Sub extends Super

scala> implicitly[(Super ∨ String) <:< ¬[Super]]
res0: <:<[?[Super,String],(Super) => Nothing] = 

scala> implicitly[(Super ∨ String) <:< ¬[Sub]]
res2: <:<[?[Super,String],(Sub) => Nothing] = 

scala> implicitly[(Super ∨ String) <:< ¬[Any]]
error: could not find implicit value for parameter
       e: <:<[?[Super,String],(Any) => Nothing]
       implicitly[(Super ? String) <:< ?[Any]]
                 ^
 scala> implicitly[D[¬[Sub]] <:< D[(Super ∨ String)]]
error: could not find implicit value for parameter
       e: <:<[D[(() => Sub) => Sub],D[?[Super,String]]]
       implicitly[D[?[Sub]] <:< D[(Super ? String)]]
                 ^
trait D[-A]

scala> implicitly[D[D[Super]] <:< D[D[Super] with D[String]]]
res0: <:<[D[D[Super]],D[D[Super] with D[String]]] = 

scala> implicitly[D[D[Sub]] <:< D[D[Super] with D[String]]]
res1: <:<[D[D[Sub]],D[D[Super] with D[String]]] = 

scala> implicitly[D[D[Any]] <:< D[D[Super] with D[String]]]
error: could not find implicit value for parameter
       e: <:<[D[D[Any]],D[D[Super] with D[String]]]
       implicitly[D[D[Any]] <:< D[D[Super] with D[String]]]
                 ^
class D[-A] (v: A) {
  def get[T <: A] = v match {
    case x: T => x
  }
}

implicit def neg[A](x: A) = new D[D[A]]( new D[A](x) )

def size(t: D[D[Int] with D[String]]) = t match {
  case x: D[D[Int]] => x.get[D[Int]].get[Int]
  case x: D[D[String]] => x.get[D[String]].get[String]
  case x: D[D[Double]] => x.get[D[Double]].get[Double]
}
def size(t: D[D[Super] with D[String]]) = t match {
  case x: D[D[Super]] => x.get[D[Super]].get[Super]
  case x: D[D[String]] => x.get[D[String]].get[String]
}

scala> size( new Super )
res7: Any = Super@1272e52

scala> size( new Sub )
res8: Any = Sub@1d941d7
object Union {
  import scala.language.higherKinds

  sealed trait ¬[-A]

  sealed trait TSet {
    type Compound[A]
    type Map[F[_]] <: TSet
  }

  sealed trait ∅ extends TSet {
    type Compound[A] = A
    type Map[F[_]] = ∅ 
  }

  // Note that this type is left-associative for the sake of concision.
  sealed trait ∨[T <: TSet, H] extends TSet {
    // Given a type of the form `∅ ∨ A ∨ B ∨ ...` and parameter `X`, we want to produce the type
    // `¬[A] with ¬[B] with ... <:< ¬[X]`.
    type Member[X] = T#Map[¬]#Compound[¬[H]] <:< ¬[X]

    // This could be generalized as a fold, but for concision we leave it as is.
    type Compound[A] = T#Compound[H with A]

    type Map[F[_]] = T#Map[F] ∨ F[H]
  }

  def foo[A : (∅ ∨ String ∨ Int ∨ List[Int])#Member](a: A): String = a match {
    case s: String => "String"
    case i: Int => "Int"
    case l: List[_] => "List[Int]"
  }

  foo(42)
  foo("bar")
  foo(List(1, 2, 3))
  foo(42d) // error
  foo[Any](???) // error
}
type v[A,B] = Either[Option[A], Option[B]]

private def L[A,B](a: A): v[A,B] = Left(Some(a))
private def R[A,B](b: B): v[A,B] = Right(Some(b))  
// TODO: for more use scala macro to generate this for up to 22 types?
implicit def a2[A,B](a: A): v[A,B] = L(a)
implicit def b2[A,B](b: B): v[A,B] = R(b)
implicit def a3[A,B,C](a: A): v[v[A,B],C] = L(a2(a))
implicit def b3[A,B,C](b: B): v[v[A,B],C] = L(b2(b))
implicit def a4[A,B,C,D](a: A): v[v[v[A,B],C],D] = L(a3(a))
implicit def b4[A,B,C,D](b: B): v[v[v[A,B],C],D] = L(b3(b))    
implicit def a5[A,B,C,D,E](a: A): v[v[v[v[A,B],C],D],E] = L(a4(a))
implicit def b5[A,B,C,D,E](b: B): v[v[v[v[A,B],C],D],E] = L(b4(b))

type JsonPrimtives = (String v Int v Double)
type ValidJsonPrimitive[A] = A => JsonPrimtives

def test[A : ValidJsonPrimitive](x: A): A = x 

test("hi")
test(9)
// test(true)   // does not compile
def foo(xs: (String | Int)*) = xs foreach {
   case _: String => println("str")
   case _: Int => println("int")
}
trait Inv[-X]
type Or[U,T] = {
    type pf[X] = (Inv[U] with Inv[T]) <:< Inv[X]
}
// use

class A; class B extends A; class C extends B

def foo[X : (B Or String)#pf] = {}

foo[B]      // OK
foo[C]      // OK
foo[String] // OK
foo[A]      // ERROR!
foo[Number] // ERROR!
def foo[X](implicit ev : (B with String) <:< X) = {}
trait Inv[-X]
def foo[X](implicit ev : (Inv[B] with Inv[String]) <:< Inv[X]) = {}
trait Inv[-X]
type BOrString[X] = (Inv[B] with Inv[String]) <:< Inv[X]
def foo[X](implicit ev : BOrString[X]) = {}
def foo[X : BOrString] = {}
type Or[U,T][X] = (Inv[U] with Inv[T]) <:< Inv[X]
trait Inv[-X]
type Or[U,T] = {
    type pf[X] = (Inv[U] with Inv[T]) <:< Inv[X]
}
bar(new AnyRef{ type Y = Int }) // works!
def foo[X : (B Or String)#pf] = {}
type Or[U,T] = {
    type pf[X] = ((U => _) with (T => _)) <:< (X => _)
} 
sealed class Expr
case class Var   (x: String)          extends Expr
case class Apply (f: Expr, e: Expr)   extends Expr
case class Lambda(x: String, e: Expr) extends Expr
sbt new lampepfl/dotty.g8
scala> def foo(xs: (Int | String)*) = xs foreach {
     |   case _: String => println("str")
     |   case _: Int => println("int")
     | }
def foo(xs: (Int | String)*): Unit

scala> foo(2,"2","acc",-223)                                                    
int
str
str
int