从scala中的功能编程中查看IO Monad
的签名的一部分:
trait IO[+A] { self =>
def run: A
def map[B](f: A => B): IO[B] =
new IO[B] { def run = f(self.run) }
我了解,IO[+A]
表示IO
类型采用" A或其子类"的类型参数。
查看def map[B]...
,B
是此功能涉及的一种类型。使用map[B](f: A => B): IO[B]
很有用,因为据我了解,您可以将B
列为f
的返回类型,以及IO
的返回类型参数?
因此,以下实现将导致编译时间问题:
map(f: Int => String): IO[Int]
我不确定您在这种情况下通过"实现"的意思: map(f: Int => String): IO[Int]
。如果您是指调用map
传递函数Int => String
,则返回IO[String]
- callee不会在返回哪种类型的情况下获得发言权。
如果您是指使用override def map(f: Int => String): IO[String]
的map
的实现(您不应该这样做),那么不是 覆盖任何东西,因为在覆盖时无法删除类型参数,并且您也不能更改它收到的参数的类型,并且可以将返回类型更改为子类型,但是IO[String]
不是IO[B]
的子类型,因此也不同。
,因此+A
与T <: A
相似。这意味着"适用于包括a的所有子类型"。此"限制"在这里很有用,因为您应该将f
函数传递给map
方法,并且将其限制在特定类型的A
及其子类型中。因此,当您扩展班级中的特质时,您可以在typesafe时替换f
。
B
这是将f
应用于A
的结果。由于它是一个单子,您不仅可以返回B
,还可以返回IO[B]
。换句话说,它可能失败,您可能会被B
包裹在"成功"或某种"失败"中。
请注意,self
的类型是+A
,而新创建的IO[B]
实际上没有计算任何内容,它只是围绕run
的结果,该结果必须是B
。由于您期望在IO中发生失败,并且由于它是一个单子,因此您可以将f(self.run)
的应用程序包裹起来,从而创建Monad IO[B]
(如map
方法签名所承诺)。
最后,正如您所说的map(f: Int => String): IO[Int]
不应编译的,因为Int
不是String
的子类型。