这引出了一个问题:为什么我要将 IO[B] 转换为 StreamT[IO, B] ?答案是"to take advantage of composition possibilities" . 假设你有一个函数 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]
16
我在论文中遇到的另一种解除用法(不一定是与Scala相关的)正在使用 f: List[A] -> List[B] (或集合,多集合,......)重载 f: A -> B 中的函数 . 这通常用于简化形式化,因为无论 f 是应用于单个元素还是多个元素都无关紧要 .
4 回答
有一些用法:
PartialFunction
请记住,
PartialFunction[A, B]
是为域A
的某个子集定义的函数(由isDefinedAt
方法指定) . 你可以"lift"PartialFunction[A, B]
成Function[A, Option[B]]
. 也就是说,在整个A
上定义的函数,但其值为Option[B]
的类型这是通过在
PartialFunction
上显式调用方法lift
来完成的 .方法
您可以"lift"将方法调用到函数中 . 这称为eta-expansion(感谢Ben James) . 例如:
我们通过应用下划线将方法提升为函数
注意方法和函数之间的根本区别 .
res0
是(函数)类型的 instance (即它是一个值)(Int => Int)
Functors
一个仿函数(由 scalaz 定义)是"container"(我使用极松散的术语),
F
这样,如果我们有一个F[A]
和一个函数A => B
,那么我们可以得到一个F[B]
(想想,例如,F = List
和map
方法)我们可以对此属性进行如下编码:
这是同形的,能够"lift"函数
A => B
进入仿函数的域 . 那是:也就是说,如果
F
是一个仿函数,并且我们有一个函数A => B
,我们有一个函数F[A] => F[B]
. 您可以尝试实现lift
方法 - 这非常简单 .Monad变形金刚
正如hcoopz在下面所说(我刚刚意识到这会让我免于编写大量不必要的代码),术语"lift"在 Monad Transformers 中也有意义 . 回想一下,monad变换器是一种相互叠加的方式(monad不构成) .
例如,假设您有一个返回
IO[Stream[A]]
的函数 . 这可以转换为monad变压器StreamT[IO, A]
. 现在你可能希望"lift"其他一些值IO[B]
也许它也是StreamT
. 你可以这样写:或这个:
这引出了一个问题:为什么我要将
IO[B]
转换为StreamT[IO, B]
?答案是"to take advantage of composition possibilities" . 假设你有一个函数f: (A, B) => C
我在论文中遇到的另一种解除用法(不一定是与Scala相关的)正在使用
f: List[A] -> List[B]
(或集合,多集合,......)重载f: A -> B
中的函数 . 这通常用于简化形式化,因为无论f
是应用于单个元素还是多个元素都无关紧要 .这种重载通常是以声明方式完成的,例如,
要么
或者必要的,例如,
注意任何延伸
PartialFunction[Int, A]
的集合(正如oxbow_lakes所指出的)可能被解除;因此,例如它将部分函数转换为总函数,其中集合中未定义的值映射到
None
,此外,
这显示了一种简洁的方法来避免索引超出范围的异常 .
还有提升,这是提升的逆过程 .
如果提升定义为
然后解开是
Scala标准库将Function.unlift定义为
例如,play-json库提供unlift来帮助构建JSON serialisers: