How to Make Fibonacci Confusing
前几天同事发了这么一段代码:
(fn =>
(f => f(f))(f => fn(n => f(f)(n))))(g => n =>
[1, 2].indexOf(n) > -1 ? 1 : g(n - 1) + g(n - 2)
)(10);
你看这段代码时,一定是这样的心情:

好端端的 斐波那契 是怎么变成这样的,因吹斯听,我们来回放一下。
从正常的写法开始:
const fib = n =>
[1, 2].indexOf(n) >= 0
? 1
: fib(n - 1) + fib(n - 2);
为了让上面看起来不像递归,改写一下,把递归调用改成调用参数 g:
const wrappedFib = g => n =>
[1, 2].indexOf(n) >= 0
? 1
: g(n - 1) + g(n - 2);
不管 g 传什么,例如就传 null,1,2 两项都可以计算了,因为压根和 g 无关。
wrappedFib(null)(1);
wrappedFib(null)(2);
如果要计算第 3 项,那么 g 可以是 wrappedFib(null)。
let g = wrappedFib(null);
wrappedFib(g)(3);
同理,第 4 项:
let g = wrappedFib(wrappedFib(null));
wrappedFib(g)(4);
第 5 项......第 N 项我就不列了。
看起来需要构造一个 g,它由无限层 wrappedFib 组成。
递归的思想:
const g = n => wrappedFib(g)(n);
运行一下试试吧:
const wrappedFib = g => n =>
[1, 2].indexOf(n) >= 0
? 1
: g(n - 1) + g(n - 2);
const g = n => wrappedFib(g)(n);
console.log(wrappedFib(g)(10));
g本身是由无限层wrappedFib组成的,所以wrappedFib(g)和g是等价的。因此也可以直接调
console.log(g(10))。
const g = n => wrappedFib(g)(n);
又看到了明显的递归对不对,试着把它藏起来。思想跟刚开始一样,通过参数传进来。
这段要花点时间理解。
const g = (f => n =>
wrappedFib(f(f))(n))(f => n =>
wrappedFib(f(f))(n)
);
函数本身和函数传参一样,换个写法:
const g = (f => f(f))(f => n =>
wrappedFib(f(f))(n)
);
能到这里,我们和最终的代码已经很接近了。
把 g 中的 wrappedFib 去掉,通过参数 fn 传进来。
const gWaitForWrappedFib = fn =>
(f => f(f))(f => n => fn(f(f))(n));
const g = gWaitForWrappedFib(wrappedFib);
好了,去掉常量的定义,全部连起来吧:
(fn =>
(f => f(f))(f => fn(n => f(f)(n))))(g => n =>
[1, 2].indexOf(n) > -1 ? 1 : g(n - 1) + g(n - 2)
)(10);
拆解这段代码挺烧脑,膜拜一下代码的作者。
更新
读《The Little Schemer》时发现:这段代码和
Y-Combinator有关。Mark,以后再写个续。
How to Make Fibonacci Confusing的更多相关文章
- 算法与数据结构(九) 查找表的顺序查找、折半查找、插值查找以及Fibonacci查找
今天这篇博客就聊聊几种常见的查找算法,当然本篇博客只是涉及了部分查找算法,接下来的几篇博客中都将会介绍关于查找的相关内容.本篇博客主要介绍查找表的顺序查找.折半查找.插值查找以及Fibonacci查找 ...
- #26 fibonacci seqs
Difficulty: Easy Topic: Fibonacci seqs Write a function which returns the first X fibonacci numbers. ...
- 关于java的递归写法,经典的Fibonacci数的问题
经典的Fibonacci数的问题 主要想展示一下迭代与递归,以及尾递归的三种写法,以及他们各自的时间性能. public class Fibonacci { /*迭代*/ public static ...
- 斐波拉契数列(Fibonacci) 的python实现方式
第一种:利用for循环 利用for循环时,不涉及到函数,但是这种方法对我种小小白来说比较好理解,一涉及到函数就比较抽象了... >>> fibs = [0,1] >>&g ...
- fibonacci数列(五种)
自己没动脑子,大部分内容转自:http://www.jb51.net/article/37286.htm 斐波拉契数列,看起来好像谁都会写,不过它写的方式却有好多种,不管用不用的上,先留下来再说. 1 ...
- POJ3070 Fibonacci[矩阵乘法]
Fibonacci Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 13677 Accepted: 9697 Descri ...
- Fibonacci 数列算法分析
/************************************************* * Fibonacci 数列算法分析 ****************************** ...
- 算法系列:Fibonacci
Copyright © 1900-2016, NORYES, All Rights Reserved. http://www.cnblogs.com/noryes/ 欢迎转载,请保留此版权声明. -- ...
- UVa #11582 Colossal Fibonacci Numbers!
巨大的斐波那契数 The i'th Fibonacci number f (i) is recursively defined in the following way: f (0) = 0 and ...
随机推荐
- gitbook 入门教程之环境要求
gitbook 是基于 node.js 的命令行工具,首先需要安装并配置好 node.js 环境,然后才能安装gitbook 相关工具. 由于安装工具全部都是国外网站,因此速度可能会很慢,也可能需要F ...
- 如何用RSS订阅?
本文由云+社区发表 摘要:我们常常会有订阅别人文章的需求,有更新的时候希望能有提醒的功能,RSS就是这样一个订阅的方式.很多网站上看到RSS的入口,点进去以后总是显示一堆的XML代码,我们来看看怎么使 ...
- python3.6+selenium3.13 自动化测试项目实战一(增加自动发送邮件报告接口)
说明: 继实战项目一的基础上添加自动发送报告邮件接口,代码有部分调整,可以结合实战一和上篇文章学习 变动: 1.增加文本文档SendToUserinfo.txt 用来保存邮件接收者的信息 2.修改测试 ...
- 广州 office365的开发者训练营交流活动简报
2018年10月13日,在 微软广州办公室(广州市天河区太古汇1座28层微软广州办公室) 成功举办了office365的开发者训练营,本活动在微软官网的地址: https://www.microsof ...
- javascript面向对象理解的补充
<html> <head> <title>js inherit demo</title> <meta http-equiv="pragm ...
- [Swift]LeetCode1034.边框着色 | Coloring A Border
Given a 2-dimensional grid of integers, each value in the grid represents the color of the grid squa ...
- Yii框架基础增删查改
返回一条数据 Country::find()->one(); 返回所有数据 Country::find()->all(); 返回记录的数量 $country =Country::find( ...
- Mac电脑上一款非常时尚高清的动态壁纸Living Wallpaper HD
很多朋友Mac电脑上都喜欢用动态壁纸,Living Wallpaper HD是本人尝试的一款非常不错的高清动态壁纸.有时钟.天气等各种组建,非常时尚美观. Living Wallpaper HD下载地 ...
- Docker & ASP.NET Core (1):把代码连接到容器
和这种蛋糕一样,Docker的容器和镜像也是使用类似的分层文件系统构建而成的. 这样做的好处就是可以节省硬盘空间,也利于复用等等.因为Docker基于镜像创建容器的时候,其镜像是共享的:而且镜像里面的 ...
- SQL Server常用函数使用方法(学习)
1.转载至 https://www.cnblogs.com/Brambling/p/6779434.html Substring()函数,用于截取字符串方法,三个参数 参数1:用于指定要操作的字符串 ...