有时,当我在Scala生态系统中阅读文章时,我读到了术语“提升”/“解除”。不幸的是,没有解释这到底意味着什么。我做了一些研究,似乎举重与功能价值或类似的东西有关,但我找不到一篇文章,以初学者友好的方式解释起重实际上是什么。
在电梯框架中还有更多的混乱,这个框架以它的名字命名,但它无助于回答这个问题。
Scala中的“提升”是什么?
发布于 2013-07-31 08:31:39
有几种用法:
PartialFunction
记住,PartialFunction[A, B]是为域A的某些子集定义的函数(由isDefinedAt方法指定)。您可以将PartialFunction[A, B]“提升”到Function[A, Option[B]]中。也就是说,在整个A上定义的函数,但其值为Option[B]类型。
这是通过在lift上显式调用PartialFunction实现的。
scala> val pf: PartialFunction[Int, Boolean] = { case i if i > 0 => i % 2 == 0}
pf: PartialFunction[Int,Boolean] = <function1>
scala> pf.lift
res1: Int => Option[Boolean] = <function1>
scala> res1(-1)
res2: Option[Boolean] = None
scala> res1(1)
res3: Option[Boolean] = Some(false)方法
您可以将方法调用“提升”到函数中。这被称为eta-扩展(感谢本詹姆斯的这一点)。例如:
scala> def times2(i: Int) = i * 2
times2: (i: Int)Int我们通过应用下划线将一个方法提升为一个函数。
scala> val f = times2 _
f: Int => Int = <function1>
scala> f(4)
res0: Int = 8注意方法和函数之间的根本区别。res0是(函数)类型(Int => Int)的实例(即值)
函子
函子(由定义)是一些“容器”(我非常宽松地使用这个术语),F使得,如果我们有一个F[A]和一个函数A => B,那么我们就可以得到一个F[B] (例如,F = List和map方法)。
我们可以将该属性编码如下:
trait Functor[F[_]] {
def map[A, B](fa: F[A])(f: A => B): F[B]
}这与能够将函数A => B“提升”到函子的区域是同构的。这就是:
def lift[F[_]: Functor, A, B](f: A => B): F[A] => F[B]也就是说,如果F是一个函子,我们有一个函数A => B,我们有一个函数F[A] => F[B]。您可以尝试实现lift方法--它非常简单。
Monad变压器
正如hcoopz在下面所述(我刚刚意识到这可以避免编写大量不必要的代码),术语"lift“在Monad 中也有意义。回想一下,单台变压器是一种“堆叠”在一起的单元组( monad不作曲)。
例如,假设您有一个返回IO[Stream[A]]的函数。这可以转换为单变压器StreamT[IO, A]。现在,您可能希望“提升”一些其他值--一个IO[B] --也许它也是一个StreamT。您可以这样写:
StreamT.fromStream(iob map (b => Stream(b)))或者这个:
iob.liftM[StreamT]这就引出了一个问题:为什么我要将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]发布于 2015-04-21 07:37:16
注意,任何扩展PartialFunction[Int, A]的集合(如oxbow_lakes所指出的)都可能被取消,例如
Seq(1,2,3).lift
Int => Option[Int] = <function1>将部分函数转换为总函数,其中未在集合中定义的值映射到None,
Seq(1,2,3).lift(2)
Option[Int] = Some(3)
Seq(1,2,3).lift(22)
Option[Int] = None此外,
Seq(1,2,3).lift(2).getOrElse(-1)
Int = 3
Seq(1,2,3).lift(22).getOrElse(-1)
Int = -1这显示了一种避免索引超出界限异常的简洁方法。
发布于 2013-07-31 08:43:10
我在论文(不一定是Scala相关的)中遇到的提升的另一个用法是使用f: A -> B (或集合、多集、.)从f: List[A] -> List[B]重载函数。这通常用于简化形式化,因为无论f是应用于单个元素还是多个元素,都不重要。
这种重载通常是通过声明方式完成的,例如,
f: List[A] -> List[B]
f(xs) = f(xs(1)), f(xs(2)), ..., f(xs(n))或
f: Set[A] -> Set[B]
f(xs) = \bigcup_{i = 1}^n f(xs(i))或者说是必要的,例如,
f: List[A] -> List[B]
f(xs) = xs map fhttps://stackoverflow.com/questions/17965059
复制相似问题