scala如何处理更高类型?

时间:2014-12-26 10:19:40

标签: scala generics

在我的理解中:List,Option是具有* - >形状的种类。 * scala中的那种是否与Haskell中的相同?

如果它们相同,则List [Int]和List [String]是两种不同的类型。

但是,以下代码会显示错误double definition,其中显示have same type after erasure

  def fun1(a:Option[String]):Option[String] = a
  def fun1(a:Option[Integer]):Option[Integer] = a

  def fun2(a:List[String]) = a(0) + a(1)
  def fun2(a:List[Int]) = (a(0) + a(1)).toString

1 个答案:

答案 0 :(得分:3)

这部分是Java遗留问题。泛型类型参数在运行时不存在。 List[Int]只是List。从理论上讲,可以在编译时选择正确的实现,但是反思 - 他们是一样的。

在Haskell中,您没有函数重载,您必须为函数指定不同的名称。无论如何,这是一个好习惯。实际上,即使使用Haskell类型类,也不能为[Int][String]提供不同的实现,而不启用危险的语言扩展(FlexibleInstances)。

编辑:java示例:

package foo;

import java.util.List;

class Foo {
  void foo(List<Double> arr) {}
  void foo(List<String> arr) {}
}

失败并出现类似错误

foo.java:7: error: name clash: foo(List<String>) and foo(List<Double>) have the same erasure
  void foo(List<String> arr) {}
       ^
1 error

使用FlexibleInstances扩展名的

{-# LANGUAGE FlexibleInstances #-}

class Foo a where
  foo :: a -> String

instance Foo (Maybe String) where
  foo = maybe "" id

instance Foo (Maybe Int) where
  foo = maybe "" show

它会起作用:

*Main> foo (Just "bar")
"bar"

然而,您可以使用FlexibleInstances s:

轻松实现此示例而不使用newtype
class Foo a where
  foo :: a -> String

newtype MaybeString = MaybeString (Maybe String)
newtype MaybeInt = MaybeInt (Maybe Int)

instance Foo MaybeString where
  foo (MaybeString ms) = maybe "" id ms

instance Foo MaybeInt where
  foo (MaybeInt mi) = maybe "" show mi

*Main> foo (MaybeString (Just "bar"))
"bar"

为什么FlexibleInstances有危险?这是一个值得拥有StackOverflow线程的问题。简而言之:引入不可判定的情况非常容易,即编译器不知道要选择哪个实例:

class Foo a where
  foo :: a -> String

newtype MaybeString = MaybeString (Maybe String)
newtype MaybeInt = MaybeInt (Maybe Int)

instance Foo MaybeString where
  foo (MaybeString ms) = maybe "" id ms

instance Foo MaybeInt where
  foo (MaybeInt mi) = maybe "" show mi

如果我们尝试与之前相同的示例输入,则会收到错误:

Overlapping instances for Foo (Maybe [Char])
  arising from a use of ‘foo’
Matching instances:
  instance Foo (Maybe String) -- Defined at Example.hs:6:10
  instance Show a => Foo (Maybe a) -- Defined at Example.hs:9:10
In the expression: foo (Just "bar")
In an equation for ‘it’: it = foo (Just "bar")

您也可以在Scala中使用类型类方法。由于它依赖于implicits,并且您可以显式指定隐式参数,因此该方法比Haskell更安全。

trait Foo[A] {
  def foo(opt: Option[A]): String
}

implicit val fooString: Foo[String] = new Foo[String] {
  def foo(opt: Option[String]): String = opt match {
    case Some(value) => value + " is string"
    case None        => ""
  }
}

implicit def fooA[A]: Foo[A] = new Foo[A] {
  def foo(opt: Option[A]): String = opt match {
    case Some(value) => value.toString
    case None        => ""
  }
}

def foo[A](x: Option[A])(implicit fInstance: Foo[A]): String =
  fInstance.foo(x)

似乎 scalac 选择最具体的实例:

scala> foo(Option("bar"))
res4: String = bar is string

scala> foo(Option(2))
res5: String = 2

然而,即使fooA,我们也可以强制 scalac 使用String

scala> foo(Option("bar"))(fooA)
res6: String = bar