首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >什么是“提升”在Scala?

什么是“提升”在Scala?
EN

Stack Overflow用户
提问于 2013-07-31 08:16:23
回答 4查看 45.5K关注 0票数 281

有时,当我在Scala生态系统中阅读文章时,我读到了术语“提升”/“解除”。不幸的是,没有解释这到底意味着什么。我做了一些研究,似乎举重与功能价值或类似的东西有关,但我找不到一篇文章,以初学者友好的方式解释起重实际上是什么。

电梯框架中还有更多的混乱,这个框架以它的名字命名,但它无助于回答这个问题。

Scala中的“提升”是什么?

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2013-07-31 08:31:39

有几种用法:

PartialFunction

记住,PartialFunction[A, B]是为域A的某些子集定义的函数(由isDefinedAt方法指定)。您可以将PartialFunction[A, B]“提升”到Function[A, Option[B]]中。也就是说,在整个A上定义的函数,但其值为Option[B]类型。

这是通过在lift上显式调用PartialFunction实现的。

代码语言:javascript
复制
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-扩展(感谢本詹姆斯的这一点)。例如:

代码语言:javascript
复制
scala> def times2(i: Int) = i * 2
times2: (i: Int)Int

我们通过应用下划线将一个方法提升为一个函数。

代码语言:javascript
复制
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 = Listmap方法)。

我们可以将该属性编码如下:

代码语言:javascript
复制
trait Functor[F[_]] { 
  def map[A, B](fa: F[A])(f: A => B): F[B]
}

这与能够将函数A => B“提升”到函子的区域是同构的。这就是:

代码语言:javascript
复制
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。您可以这样写:

代码语言:javascript
复制
StreamT.fromStream(iob map (b => Stream(b)))

或者这个:

代码语言:javascript
复制
iob.liftM[StreamT]

这就引出了一个问题:为什么我要将IO[B]转换为StreamT[IO, B]__?答案是“利用构图的可能性”。假设您有一个函数f: (A, B) => C

代码语言:javascript
复制
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]
票数 319
EN

Stack Overflow用户

发布于 2015-04-21 07:37:16

注意,任何扩展PartialFunction[Int, A]的集合(如oxbow_lakes所指出的)都可能被取消,例如

代码语言:javascript
复制
Seq(1,2,3).lift
Int => Option[Int] = <function1>

将部分函数转换为总函数,其中未在集合中定义的值映射到None

代码语言:javascript
复制
Seq(1,2,3).lift(2)
Option[Int] = Some(3)

Seq(1,2,3).lift(22)
Option[Int] = None

此外,

代码语言:javascript
复制
Seq(1,2,3).lift(2).getOrElse(-1)
Int = 3

Seq(1,2,3).lift(22).getOrElse(-1)
Int = -1

这显示了一种避免索引超出界限异常的简洁方法。

票数 26
EN

Stack Overflow用户

发布于 2013-07-31 08:43:10

我在论文(不一定是Scala相关的)中遇到的提升的另一个用法是使用f: A -> B (或集合、多集、.)从f: List[A] -> List[B]重载函数。这通常用于简化形式化,因为无论f是应用于单个元素还是多个元素,都不重要。

这种重载通常是通过声明方式完成的,例如,

代码语言:javascript
复制
f: List[A] -> List[B]
f(xs) = f(xs(1)), f(xs(2)), ..., f(xs(n))

代码语言:javascript
复制
f: Set[A] -> Set[B]
f(xs) = \bigcup_{i = 1}^n f(xs(i))

或者说是必要的,例如,

代码语言:javascript
复制
f: List[A] -> List[B]
f(xs) = xs map f
票数 21
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/17965059

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档