查看来自Functional Programming in 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]
答案 0 :(得分:3)
我不确定在这种情况下“实施”是什么意思:map(f: Int => String): IO[Int]
。如果你的意思是调用map
传递函数Int => String
,那么返回IO[String]
- 被调用者不会对返回的类型有所说明。
如果您的意思是用map
覆盖override def map(f: Int => String): IO[String]
(您不应该这样做)的实现,那么不会覆盖任何内容,因为您不能在覆盖时删除类型参数,并且您无法更改其接收的参数类型,并且可以将返回类型更改为子类型,但IO[String]
不是IO[B]
的子类型所以这也是不同的。
答案 1 :(得分:1)
因此+A
与T <: A
的含义相似。这意味着“对于A的所有亚型,包括A”。这个“限制”在这里很有用,因为您应该将f
函数传递给map
方法,并且您将其限制为特定类型A
并且它是子类型。因此,当您在类中扩展特征时,您可以在类型安全时替换f
。
B
这是将f
应用于A
的结果。由于它是Monad,因此您不仅可以获得B
,还可以获得IO[B]
。换句话说,它可能会失败,你可能会被B
包裹在“成功”或某种“失败”中。
请注意,self
的类型为+A
,而新创建的IO[B]
实际上并未计算任何内容,它只包含run
的结果是B
。由于您希望在IO中发生故障,并且因为它是Monad,因此您可以使用f(self.run)
创建monad IO[B]
(由map
方法签名承诺)的应用程序结果。
最后,正如您所说map(f: Int => String): IO[Int]
不应该编译,因为Int
不是String
的子类型。