这就引出了一个问题:* 为什么要将IO[B]转换为StreamT[IO, B]?*.答案是“利用组合的可能性”。假设你有一个函数f: (A, B) => C
lazy val f: (A, B) => C = ???
val cs =
for {
a <- as //as is a StreamT[IO, A]
b <- bs.liftM[StreamT] //bs was just an IO[B]
}
yield f(a, b)
cs.toStream //is a Stream[IO[C]], cs was a StreamT[IO, C]
4条答案
按热度按时间slsn1g291#
有几种用法:
PartialFunction
记住,
PartialFunction[A, B]
是为域A
的某个子集定义的函数(由isDefinedAt
方法指定)。您可以将PartialFunction[A, B]
“提升”为Function[A, Option[B]]
。也就是说,一个定义在A
的 whole 上的函数,但其值的类型为Option[B]
这是通过显式调用
PartialFunction
上的方法lift
来完成的。方法
您可以将方法调用“提升”到函数中。这被称为 * eta-扩展 *(感谢@Ben James)。例如:
我们通过使用 * 下划线 * 将一个方法提升为一个函数
注意方法和函数之间的根本区别。
res0
是一个示例(即它是(函数)类型(Int => Int)
的 * 值 *)函数
一个 functor(由scalaz定义)是一个“容器”(我非常松散地使用术语 *),
F
,如果我们有一个F[A]
和一个函数A => B
,那么我们可以得到一个F[B]
(例如,想想F = List
和map
方法)我们可以将此属性编码如下:
这同构于能够将函数
A => B
“提升”到函子的域中。即:也就是说,如果
F
是一个函子,我们有一个函数A => B
,我们有一个函数F[A] => F[B]
。您可以尝试实现lift
方法-它非常简单。Monad Transformers
正如 hcoopz 在下面所说的(我刚刚意识到这将使我免于编写大量不必要的代码),术语“lift”在Monad Transformers中也有含义。回想一下,monad转换器是一种将monad“堆叠”在彼此之上的方法(monad不组合)。
例如,假设你有一个返回
IO[Stream[A]]
的函数。这可以转换为monad转换器StreamT[IO, A]
。现在,您可能希望“提升”一些其他值IO[B]
,也许它也是StreamT
。你可以这样写:或者这个:
这就引出了一个问题:* 为什么要将
IO[B]
转换为StreamT[IO, B]
?*.答案是“利用组合的可能性”。假设你有一个函数f: (A, B) => C
bakd9h0s2#
注意任何扩展到
PartialFunction[Int, A]
的集合(如oxbow_lakes所指出的)都可以被提升;例如其将部分函数转变为其中集合中未定义的值被Map到
None
上的总函数,此外,委员会认为,
这显示了一种避免 index out of bounds 异常的简洁方法。
xfyts7mz3#
我在论文中遇到的另一个 lifting 的用法(不一定是与Scala相关的)是用
f: List[A] -> List[B]
(或集合,多集合,...)从f: A -> B
重载函数。这通常用于简化形式化,因为f
应用于单个元素还是多个元素并不重要。这种重载通常是声明性的,例如,
或
或者强制地,例如,
dffbzjpn4#
还有一种是 unlifting,这是提升的逆过程。
如果提升定义为
将部分函数
PartialFunction[A, B]
转化为总函数A => Option[B]
则解除是
将全函数
A => Option[B]
转换为部分函数PartialFunction[A, B]
Scala标准库将
Function.unlift
定义为例如,play-json库提供了unlift来帮助构建JSON序列化器: