热门标签 | HotTags
当前位置:  开发笔记 > 前端 > 正文

程序设计语言中的语法糖

语法糖是什么呢?按我现在的理解,如果一门语言没有某个语法,照样可以通过其它更通用的方式来表达某种语义。这种语法的引入,只不过是让表达语义更方便了。那么这个语法,就叫语法糖。Scheme中有两个关键

语法糖是什么呢?按我现在的理解,如果一门语言没有某个语法,照样可以通过其它更通用的方式来表达某种语义。这种语法的引入,只不过是 让表达语义更方便了。那么这个语法,就叫语法糖。

Scheme 中有两个关键字 lambda, let ,我目前的理解是,他们就是语法糖。

lambda

lambda 用来定义一个匿名函数。有时候,一个函数我们只在一个地方用一次,完全没必要给它定义一个名字,这时候,我们就用 lambda 定义 一个匿名函数。

如果没有 lambda ,那么我们定义函数时,会使用下面这种方式:

(define (pi-sum a b)
(define (pi-term x)
(/ 1.0 (* x (+ x 2))))
(define (pi-next x)
(+ x 4))
(sum pi-term a pi-next b))

其中像 pi-term 和 pi-next 这样的小函数,完全可以通过 lambda 定义一个匿名函数。

(define (pi-sum a b)
(sum
(lambda (x) (/ 1.0 (* x (+ x 2))))
a
(lambda (x) (+ x 4))
b))

let

let 用来定义局部变量,其实没有局部变量,我们也可以表达相应的语义,只不过有了 let ,定义起来更方便了。由于之前没有函数式语言 编程的经验,完全不知道没有局部变量要怎么办,所以还是看一个例子。

计算

f(x,y) = x(1+xy)^2 + y(1-y) + (1+xy)(1-y)

我们可以通过

a = 1 + xy
b = 1 - y
f(x, y) = xa^2 + yb + ab

来定义这个函数,这里面的 a, b 就相当于局部变量,那么在没有局部变量语法的情况下,我们怎么定义这个函数呢?

办法就是定义一个内部函数,将形式参数设定为 a, b,然后将 1 + xy 和 1-y 作为实际参数传递进去:

(define (f x y)
(define (f-helper a b)
(+ (* x (square a))
(* y b)
(* a b)))
(f-helper (+ 1 (* x y))
(- 1 y)))

而如果引入 let 这个语法糖后,定义起来就变得直观,容易多了:

(define (f x y)
(let ((a (+ 1 (* x y)))
(b (- 1 y)))
(+ (* x (square a))
(* y b)
(* a b))))

从这里可以看出,let 作用域内分两部分,一部分定义局部变量,另一部分是函数体。

通过对 SICP 这部分的学习,我明白了,什么是本质上的东西,什么是语法糖。本质上的东西是对函数及求值方式的定义,他们形式简单,功能强大, 大部分语义都可以通过这些定义出来。只是为了方便,我们引入了语法糖,来更容易地表达语义。

关于 lambda 这个词的来源,书中也有介绍,这是历史原因,源于 Alonzo Church 的 lambda 演算。lambda 演算为研究函数定义, 函数应用提供了坚实的数学基础。我还隐约记得在程序设计语言课上,老师教我们用 lambda 演算定义自然数,加法等运算法则,true/false, if/else 等等。你可以看出,这些本质的东西,可以表达非常非常多的东西,功能异常强大。

注:这是我学习 SICP 后的总结与思考,例子也都来自于此书。


推荐阅读
  • 本文详细介绍了MySQL 5.5及以上版本中事务管理的全过程,包括事务的启动、设置、锁机制以及解锁方法,旨在为开发者提供一个清晰、全面的操作指南,避免因网络资料分散而导致的学习障碍。 ... [详细]
  • 优化ListView性能
    本文深入探讨了如何通过多种技术手段优化ListView的性能,包括视图复用、ViewHolder模式、分批加载数据、图片优化及内存管理等。这些方法能够显著提升应用的响应速度和用户体验。 ... [详细]
  • Søren Kierkegaard famously stated that life can only be understood in retrospect but must be lived moving forward. This perspective delves into the intricate relationship between our lived experiences and our reflections on them. ... [详细]
  • 1:有如下一段程序:packagea.b.c;publicclassTest{privatestaticinti0;publicintgetNext(){return ... [详细]
  • C++实现经典排序算法
    本文详细介绍了七种经典的排序算法及其性能分析。每种算法的平均、最坏和最好情况的时间复杂度、辅助空间需求以及稳定性都被列出,帮助读者全面了解这些排序方法的特点。 ... [详细]
  • 本文详细探讨了Java中的24种设计模式及其应用,并介绍了七大面向对象设计原则。通过创建型、结构型和行为型模式的分类,帮助开发者更好地理解和应用这些模式,提升代码质量和可维护性。 ... [详细]
  • 深入理解C++中的KMP算法:高效字符串匹配的利器
    本文详细介绍C++中实现KMP算法的方法,探讨其在字符串匹配问题上的优势。通过对比暴力匹配(BF)算法,展示KMP算法如何利用前缀表优化匹配过程,显著提升效率。 ... [详细]
  • 机器学习中的相似度度量与模型优化
    本文探讨了机器学习中常见的相似度度量方法,包括余弦相似度、欧氏距离和马氏距离,并详细介绍了如何通过选择合适的模型复杂度和正则化来提高模型的泛化能力。此外,文章还涵盖了模型评估的各种方法和指标,以及不同分类器的工作原理和应用场景。 ... [详细]
  • 自学编程与计算机专业背景者的差异分析
    本文探讨了自学编程者和计算机专业毕业生在技能、知识结构及职业发展上的不同之处,结合实际案例分析两者的优势与劣势。 ... [详细]
  • 2023年京东Android面试真题解析与经验分享
    本文由一位拥有6年Android开发经验的工程师撰写,详细解析了京东面试中常见的技术问题。涵盖引用传递、Handler机制、ListView优化、多线程控制及ANR处理等核心知识点。 ... [详细]
  • 本文探讨了如何利用自定义URI方案和注册表编辑,在Windows操作系统中实现从Web浏览器启动本地应用程序的方法,同时强调了这一过程中的安全考虑。 ... [详细]
  • iOS 小组件开发指南
    本文详细介绍了iOS小部件(Widget)的开发流程,从环境搭建、证书配置到业务逻辑实现,提供了一系列实用的技术指导与代码示例。 ... [详细]
  • 本文介绍了Java并发库中的阻塞队列(BlockingQueue)及其典型应用场景。通过具体实例,展示了如何利用LinkedBlockingQueue实现线程间高效、安全的数据传递,并结合线程池和原子类优化性能。 ... [详细]
  • 在前两篇文章中,我们探讨了 ControllerDescriptor 和 ActionDescriptor 这两个描述对象,分别对应控制器和操作方法。本文将基于 MVC3 源码进一步分析 ParameterDescriptor,即用于描述 Action 方法参数的对象,并详细介绍其工作原理。 ... [详细]
  • Zookeeper面试常见问题解析
    本文详细介绍了Zookeeper中的ZAB协议、节点类型、ACL权限控制机制、角色分工、工作状态、Watch机制、常用客户端、分布式锁实现、默认通信框架以及消息广播和领导选举的流程。 ... [详细]
author-avatar
负能量包子玻璃包各负磁场宣泄区
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有