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

目录
相关文章
|
机器学习/深度学习 人工智能 算法
【读书笔记】Algorithms for Decision Making(1)
我自己的粗浅看法:机器学习要不是拟合逼近(经常提及的machine learning),要不就是决策过程(reinforcement learning),这本书主要讲述后者的前世今生。
268 0
【读书笔记】Algorithms for Decision Making(1)
|
算法
【读书笔记】Algorithms for Decision Making(3)
上一部分给出了概率分布的表示论。本部分将展示如何使用概率表示进行推理,即确定一组给定观察变量相关值的一个或多个未观察变量的分布。在该部分中首先介绍直接推断的办法,然后给出几种有效的近似方法。
119 0
|
算法
【读书笔记】Algorithms for Decision Making(11)
在有限维场景中,POMDP问题的精确解也经常很难计算。因而,考虑求得近似解的方法是合理的。本部分从离线近似解讨论到在线近似解,是近似方法的常规逻辑思路。
105 0
|
人工智能 vr&ar 决策智能
【读书笔记】Algorithms for Decision Making(12)
现将单智能体的核心概念扩展到多智能体系统的问题。在该系统中,可将其他智能体建模为潜在的盟友或对手,并随着时间的推移进行相应的调整。
|
机器学习/深度学习 算法 流计算
【读书笔记】Algorithms for Decision Making(6)
对于较大状态空间的问题,计算精确解需要极大的内存量,因而考虑近似解的方法。常使用approximate dynamic programming的方法去寻求近似解,进而使用在线方法实现实时计算。
119 0
【读书笔记】Algorithms for Decision Making(6)
|
机器学习/深度学习
【读书笔记】Algorithms for Decision Making(7)
策略搜索即搜索策略空间,而无需直接计算值函数。策略空间的维数通常低于状态空间,并且通常可以更有效地搜索。本部分首先讨论在初始状态分布下估计策略价值的方法。然后讨论不使用策略梯度估计的搜索方法和策略梯度方法。接着介绍Actor-Critic方法用值函数的估计来指导优化。
|
机器学习/深度学习 算法 vr&ar
【读书笔记】Algorithms for Decision Making(9)
与基于模型的方法相比,无模型方法不需要构建转移函数和奖励函数的显性表示,而是直接作用于值函数建模。进一步地,考虑模拟学习来重建奖励函数。
【读书笔记】Algorithms for Decision Making(9)
|
算法 机器人
【读书笔记】Algorithms for Decision Making(10)
在这一部分将不确定性扩展到状态。具体讲,接收到的观测值与状态只有概率关系,而不是精确地观察状态。此类问题可以建模为部分可观察的马尔可夫决策过程(POMDP),但POMDP很难以最佳方式解决所有问题,因而需要引入更多的近似策略。
135 0
|
算法 关系型数据库 数据建模
【读书笔记】Algorithms for Decision Making(4)
本部分讨论从数据学习或拟合模型参数的问题,进一步讨论了从数据中学习模型结构的方法,最后对决策理论进行了简单的概述。
【读书笔记】Algorithms for Decision Making(4)
|
机器学习/深度学习 API
【读书笔记】Algorithms for Decision Making(8)
解决存在模型不确定性的此类问题是强化学习领域的主题,这是这部分的重点。解决模型不确定性的几个挑战:首先,智能体必须仔细平衡环境探索和利用通过经验获得的知识。第二,在做出重要决策后很长时间内,可能会收到奖励,因此必须将以后奖励的学分分配给以前的决策。第三,智能体必须从有限的经验中进行概括。
167 0
【读书笔记】Algorithms for Decision Making(8)

热门文章

最新文章