scala函数式编程: 严格求值与惰性求值笔记

本文探讨了Scala中的严格求值与惰性求值概念,解释了传名参数和传值参数的区别,并展示了如何通过非严格求值函数实现惰性求值。通过示例说明了惰性求值在增量计算、无限流和共递归中的应用,强调了其在节省内存和提高效率上的优势。
摘要由CSDN通过智能技术生成
先验知识
  • 传名参数和传值参数:传值参数在函数调用之前表达式会被求值,传名参数在函数调用前表达式不会被求值,而是会被包裹成一个匿名函数作为函数参数传递下去,例如参数类型为无参函数的参数就是传名参数。
  • function0是接受0个参数的函数类型。
  • () => A和A是2种类型。() => A是个函数,A是个数据类型。
  • => A 是 () => A的简写。
  • lazy关键字:
    • The difference between them is, that a val is executed when it is defined whereas a lazy val is executed when it is accessed the first time.
    • 例:val xlazy val x
严格求值和非严格(惰性)求值
  • 一个严格求值的函数总是对它的参数求值,即该参数会在函数被调用前求值。
  • 给一个函数传递一个未求值的参数,在函数中引用的地方会被求值,即scala不会缓存未求值参数的求值结果。这是因为未求值的参数是一个匿名函数,每次引用相当于对该函数求值。可以用lazy关键字来显示地缓存这个值
非严格求值函数
  • scala中非严格求值的函数接收的参数是传名参数而非传值参数。
  • scala中用() => A这种无参函数作为传名参数实现非严格求值函数。
  • on: () => A表示参数on非严格求值,其实是一个接受0个参数的函数,通常一个表达式的未求值形式称为chunk
  • 使用on()强制对on求值
一个非严格求值的例子
  • Stream[A] = Cons(h: () => A, t: () => Stream[A])
  • cons函数接受2个非严格求值参数。即() => A和() => Stream[A]
  • 所以在apply中调用cons的时候,即as.head和apply(as.tail: _)这2个参数会被系统包装为chunk。即相当于cons(() => as.head,() => apply(as.tail: _))。因此这2个参数是传名参数,不会被求值所以递归不会发生。
  • 如调用apply(1,2,3),apply只会被调用1次。返回值为Cons(() => 0,() => apply(2,3))。
  def cons[A](hd: => A, tl: => Stream[A]) = {
    lazy val head = hd
    lazy val tail = tl
    Cons(() => head, () => tail)
  }
  
  def empty[A]: Stream[A] = Empty

  //初始化时仅仅执行一次
  def apply[A](as: A*): Stream[A] = {
    println("hell")
    if (as.isEmpty) empty else cons(as.head,apply(as.tail: _*))
  }

把函数的描述和求值分离
  • 对于Stream,可以构建一个产生一系列元素的计算逻辑直到实际需要这些元素时才
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值