IT技术博客大学习 共学习 共进步
全部 移动开发 后端 数据库 AI 算法 安全 DevOps 前端 设计 开发者

标签:Functional Programming

共 7 篇相关文章

IT 累计浏览 4,389

JavaScript的闭包问题

这篇讲的是 JavaScript 闭包在循环中一个经典的陷阱。作者从一个看似简单的需求出发:在一个 `for` 循环中创建三个函数,分别打印当前的循环索引。但实际执行时,所有函数都打印了同一个值——循环结束后的最终值。 问题的根源在于闭包捕获的是变量的引用,而非创建时的快照。循环变量 `i` 在所有函数中都是同一个变量,因此函数执行时读取的都是循环结束后那个值。即使尝试在循环内用 `var n = i` 复制一份,由于 JavaScript 缺乏块级作用域,`n` 的作用域依然是整个外层函数,最终也会被后续的迭代覆盖。 作者指出,这条“不要在闭包中直接引用循环变量”的原则,适用于所有函数式语言。正确的做法是创建一个新的作用域来捕获当前迭代的值。文章演示了两种经典方案:一是通过一个额外的函数(如 `function(n){...}`)将当前 `i` 作为参数传入;二是更简洁的立即执行函数表达式(IIFE),在循环体内 `(function(n){...})(i)` 就地创建一个新作用域并传递参数。 这本质上是一个作用域与闭包机制如何相互作用的深度理解问题。掌握这个模式,能帮开发者避免在异步回调、事件监听等场景下产生难以排查的 bug。

IT 累计浏览 4,700

函数式编程

这篇讲的是函数式编程(FP)的核心理念与实用技术。作者从函数式编程的“长相”切入,首先梳理了它区别于命令式编程的三大特性:默认不可变的数据、可作为变量传递的函数,以及需要语言支持的尾递归优化。接着,文章重点剖析了几项关键技术,比如用map和reduce替代传统循环来处理集合数据,不仅代码更简洁易读,也更贴近问题的描述本身。pipeline、柯里化(currying)和高阶函数等技术则展示了如何通过组合简单函数来构建复杂逻辑。 文章并未停留在抽象概念,而是通过大量Python和C++代码示例进行了对比演示。例如,通过一个简单的计数器函数,直观展示了“不依赖也不修改外部状态,而是返回新值”这一FP准则。在Map & Reduce部分,作者对比了过程式的for循环与函数式写法在清晰度上的差异,并借助filter、reduce等函数演示了如何更优雅地解决如计算平均值这类实际问题。这种“描述要干什么,而不是怎么干”的风格,正是函数式编程提升代码可维护性的关键。 总的来说,这篇文章系统地拆解了函数式编程的思维模型与工具箱,并通过具体的语言实例阐明了其在提升代码简洁性、可读性以及并行友好性方面的优势,为理解这一编程范式提供了清晰的路径。

IT 累计浏览 2,116

Python中的闭包

这篇讲的是Python中一个既基础又容易模糊的概念——闭包。作者从一个实际的读者提问出发,用维基定义的“词法闭包”和“自由变量”两个关键词引入,并巧妙地将其比喻为一个“封闭的包裹”,包裹(函数)内部装着随身携带的自由变量。 文章的核心对比在于闭包与类:两者都实现数据封装,但闭包粒度更细,是一个只读的“函数对象”。作者接着深入剖析了闭包在Python中最常见的三个应用场景:一是构建装饰器,通过闭包持有被装饰函数并扩展其功能;二是实现类似“惰性求值”的效果,推迟某些操作(如数据库查询)的执行;三是作为`functools.partial`的原理示范,用于函数参数的提前绑定。 通过这些代码示例,文章清晰地展示了闭包如何作为函数式编程的重要工具,解决代码复用和状态保持的问题。对于想真正理解Python装饰器机制或函数式编程特性的开发者来说,这篇从概念辨析到实战落地的讲解是个不错的起点。

IT 累计浏览 2,728

尾递归与Continuation

这篇文章从一个常见的编程痛点——递归深度受限——出发,引出了两个紧密相关又层次不同的概念:尾递归与 Continuation。作者清晰地解释道,尾递归本质上是一种针对特定代码模式的编译器优化,它能将递归调用在尾部位置时转化为循环,从而避免栈溢出,常用于函数式编程语言中处理深层递归。但其优化范围仅限于尾调用位置,控制流的延续仍然是隐式的。 文章更核心的部分在于探讨 Continuation。通过 CPS(Continuation-Passing Style)转换,作者展示了如何将“程序接下来要做什么”这个隐含的控制流,显式地表示为一个可传递、可存储的“一等对象”。Continuation 能统一表达顺序执行、循环、异常甚至跳转,它将控制权交给了程序员。 两者的根本差异随之浮现:尾递归是对线性控制流的一种实现层优化,而 Continuation 则是对程序控制流本身进行建模的一种强大语言原语。文章用具体的代码示例对比了它们的表达能力,最终让读者理解,Continuation 提供了一种更根本、更灵活的控制流操控视角。这对于理解程序如何“执行”、如何管理流程至关重要。

IT 累计浏览 3,863

闭包漫谈(从抽象代数及函数式编程角度)

这篇讲的是闭包这个经典概念,但作者没有停留在语法或常见用法的层面,而是把视野拉高,从抽象代数和函数式编程两个看似不同的源头来重新审视它。 文章首先回溯了抽象代数中的“闭包”:指一个集合在某种运算下保持封闭的特性,比如整数集在加法运算下永远得到整数。这种结构性的“封闭”是代数体系的基石。接着,作者将视角转向函数式编程,这里的闭包指的是函数与其词法环境的结合体,核心在于函数能够“捕获”并携带其定义时的自由变量。 作者巧妙地建立了两者的联系:它们都关乎“边界”与“携带”。代数的闭包是运算边界的稳定性,编程的闭包是作用域边界的延伸与记忆。通过这种对比,读者能更深刻地理解,为什么函数式编程中的闭包能实现状态的封装与函数的“记忆”——它本质上是在运行时动态维持了一个属于该函数的、受保护的“小环境”,这与代数系统追求运算封闭的哲学异曲同工。 这种跨学科的视角不仅厘清了概念,也揭示了计算机科学中许多设计背后的数理逻辑。理解这一点,或许能让我们在利用闭包编写回调、实现模块化或进行函数式编程时,对其力量与边界有更自觉的把握。

IT 累计浏览 6,165

从Go看,语言设计(一)

Go语言正式版的发布标志着它从一个实验性项目走向了成熟可用。这篇讲的是作者拿到正式版后上手体验,着重从语言设计的角度,分享了其中几个令人印象深刻的特点。文章没有停留在语法的简单介绍,而是深入探讨了Go在并发模型(goroutine和channel)、接口的隐式实现、以及“少即是多”的设计哲学上如何做出取舍。作者通过具体的代码片段和场景,展示了这些设计如何影响日常编码的思维方式,比如用组合代替继承,以及显式错误处理带来的代码清晰度。对于关注编程语言演进或正在评估技术选型的开发者来说,这篇基于实际体验的观察,提供了一个理解Go核心优势与设计权衡的窗口。

IT 累计浏览 3,158

编程珠玑番外篇 -J. 高级语言是怎么来的-6

这篇讲的是Scheme语言如何从LISP中诞生,并成为现代函数式编程重要里程碑。文章从“函数作为一级对象”这个概念切入,说明在LISP中函数可以像整数一样被传递和返回,这引出了高阶函数如apply、map和reduce的基础。 然而,当函数携带“自由变量”(即非参数也非内部变量)被传来传去时,问题就来了。作者用一个具体例子演示:在早期LISP中,定义一个返回“加n”函数的addn,当测试add1时,本应得到5却得到了8。这是因为解析器采用了动态作用域,在自由变量s被使用时才去当前栈中查找其值,导致变量绑定错误。 这个问题的根源在于函数丢失了其定义时的环境信息。文章追溯到LISP实现者Steve Russell的解决方案:他引入了FUNCTION修饰符,让lambda表达式在解析时就静态绑定到当时的环境——这就是“闭包”的雏形。这种静态作用域(文法作用域)确保了自由变量不会在函数传递过程中“幽灵般”乱跑,也解决了著名的FUNARG问题。 文章最后指出,Scheme正是基于这些对作用域和闭包的规范化,才为LISP家族注入了新的活力,影响了后续包括Common LISP在内的语言发展,甚至间接成就了Paul Graham等人的商业传奇。