Practical Clojure - Functional Programming Techniques
对于通用FP技术的介绍, 参考FP基础
此处主要描述这些FP技术特性, 在clojure中的实现
First-Class Functions, 一类公民
Function作为FP中最基本的元素, 是构成所有其他的基石, 所以是一类公民...
什么是first-class?
It can be created on demand.
It can be stored in a data structure.
It can be passed as an argument to a function.
It can be returned as the value of a function.
There are two aspects to using first-class functions:
Consuming, as arguments and calling them
Functions that take other functions as arguments are extremely common. These are known as higher order functions.
Producing, creating and returning them
Not only can functions take other functions as arguments, but they can construct them and return them as values.
此特性相当强大, 后面描述的curry, comp, closure都是produce function的方法
This is one of the main reasons Lisp has historically been associated with artificial intelligence.
It was thought that functions creating other functions would allow a machine to evolve and define its own behavior.
Although self-modifying programs never quite lived up to expectations, the ability to define functions on-the-fly is nevertheless extremely powerful and useful for many everyday programming
tasks.
代码即数据, 可以运行时修改代码, 这也成为Lisp主要被用于AI的主要原因, 满足程序不停自我进化的需要.
(defn rangechecker
"Returns a function that determines if a number is in a provided range."
[min max]
(fn [num]
(and (<= num max)
(<= min num))))
user=> (def myrange (rangechecker 5 10))
user=> (myrange 7)
true
user=> (myrange 11)
false
Closures
closure和clojure读音一样, 所以在clojure中很重要?
为什么叫闭包?
简单的一句话, 保存context的函数. context一般都是在function之外的数据
因为引用的value, 其实在调用的时候, 本不应该存在的. 而实际不但存在且仅存在于function内部, 并且这个值还会伴随function的整个生命周期. 是不是很像这个value被close over在function内部...
As might be gathered from its very name, closures are a central feature in Clojure. But what, exactly, is a closure? And why do they matter so much?
Briefly stated, closures are first-class functions that contain values as well as code.
These values arethose in scope at function declaration, preserved along with the function.
Whenever a function is declared, the values locally bound to symbols it references are stored along with it.
They are “closed over” (hence the name) and maintained along with the function itself. This means that they are then available for the function’s entire lifespan and the function can be referred to as a closure.
The value of a closed-over value can’t change after the function is created, so it becomes in essence a constant for that function.
Closures和OO的关系...
One interesting property of closures is that due to their dual nature—both behavior and data—they can fulfill some roles that are assumed by objects in object-oriented languages.
Just as anonymous classes with one method are used to simulate first-class functions in Java, closures can be viewed as an object with a single method.
例子,
(defn times-n [n]
(let [x n]
(fn [y] (* y x))))
(def times-four (times-n 4))
(times-four 10)
;=> 40
Currying and Composing Functions
Using partial to Curry Functions
In Clojure, any function can be curried using the partial function.
partial takes a function as its first argument and any number of additional arguments.
It returns a function that is similar to the provided function, but with fewer arguments; it uses the additional arguments to partial instead.
partial这个名字比较形象, 部分啥? 部分参数. 第一个参数是function, 后面的参数是需要fix的那部分参数
user=> (def times-pi (partial * 3.14159)) ;*本身需要2个参数, 用partial指定一个而生成新的pi函数
不用partial你直接这样定义也是一样的, 不过用partial更简洁
(defn times-pi
"Multiplies a number by PI”
[n]
(* 3.14159 n))
Currying vs. Partial Application, 描述Currying和Partial的区别
Using comp to Compose Functions
comp takes any number of parameters: each parameter is a function.
It returns a function that is the result of calling all of its argument functions, from right to left. Starting with the rightmost, it calls the function and passes the result as the argument to the next function and so on.
user=> (def my-fn (comp – *))
user=> (my-fn 5 3) ;–(5 * 3)
(defn my-fn ;同样comp只是一种简洁的表达方式, 也可以直接写
"Returns –(x * y)”
[x y]
(- (* x y)))
comp看上去和curry没啥关系, 但是comp的每个function都只能有一个参数, 所以经常使用currying技术来减少参数
Because the functions passed to comp are required to take a single argument, it makes them particularly good candidates for using currying with partial.
user=> (def my-fn (comp (partial * 10) - *))
user=> (my-fn 5 3)
-150
Continuation-passing style, joy 7.3.4
Before wrapping up this chapter, we’re going to take time to talk about a style of programming not necessarily prevalent in Clojure, but moreso in the functional tradition: continuation-passing style.
Continuation-passing style (CPS) is a hybrid between recursion and mutual recursion, but with its own set of idioms.
这在FP基础里面也讲到, 但其实在clojure里面并没有被广泛使用. 因为可能不太需要, 因为在Haskell这种pure FP里面, CPS可以用于保证执行顺序
其实可以认为recursion是一种特殊的CPS, 每次都continue到自身
后面给的例子没太明白...
本文章摘自博客园,原文发布日期:2013-02-07
相关文章
- 在 Go 里用 CGO?这 7 个问题你要关注!
- 9款优秀的去中心化通讯软件 Matrix 的客户端
- 求职数据分析,项目经验该怎么写
- 在OKR中,我看到了数据驱动业务的未来
- 火山引擎云原生大数据在金融行业的实践
- OpenHarmony富设备移植指南(二)—从postmarketOS获取移植资源
- 《数据成熟度指数》报告:64%的企业领袖认为大多数员工“不懂数据”
- OpenHarmony 小型系统兼容性测试指南
- 肯睿中国(Cloudera):2023年企业数字战略三大趋势预测
- 适用于 Linux 的十大命令行游戏
- GNOME 截图工具的新旧截图方式
- System76 即将推出的 COSMIC 桌面正在酝酿大变化
- 2GB 内存 8GB 存储即可流畅运行,Windows 11 极致精简版系统 Tiny11 发布
- 迎接 ecode:一个即将推出的具有全新图形用户界面框架的现代、轻量级代码编辑器
- loongarch架构介绍(三)—地址翻译
- Go 语言怎么解决编译器错误“err is shadowed during return”?
- 敏捷:可能被开发人员遗忘的部分
- Denodo预测2023年数据管理和分析的未来
- 利用数据推动可持续发展
- 在 Vue3 中实现 React 原生 Hooks(useState、useEffect),深入理解 React Hooks 的