curry 和数学中定义各种符号一样,主要是用来抽取公用部分,简化代码。
比如高中数学中的累加符号Σ
对应到 Ruby 代码,我们可以定义一个 sigma lambda
sigma = -> (f, a, b) { a.upto(b).map{|n| f.(n)}.inject(:+)}
然后用 curry 定义数字累加操作和平方累加操作:
sum_of_number = sigma.curry.(-> (n) {n})
sum_of_square = sigma.curry.(-> (n) {n * n})
sum_of_number.(1,10)
sum_of_square.(1,10)
可以用相同的代码来定义累乘符号∏
pi = -> (f, a, b) { a.upto(b).map{|n| f.(n)}.inject(:*)}
更进一步,Σ和∏都是范围操作,我们可以用 curry 抽取出来:
range = -> (x, f, a, b) { x.(a.upto(b).map{|n| f.(n)})}
sigma = range.curry.(-> (r) {r.inject(:+)})
pi = range.curry.(-> (r) {r.inject(:*)})
products_of_number = pi.curry.(-> (n) {n})
products_of_number.(1,10)
cool.受教了 之前不知道还有
2.3.3 :016 > Proc.instance_methods.grep /curry/
=> [:curry]
这个方法可以用。
@alixiaomiao @lanzhiheng 不要看《计算的本质 - 深入剖析程序和计算机》啦, 看 SICP 吧, SICP 才是圣经级别读物.
《计算的本质 - 深入剖析程序和计算机》展现的只是 SICP 的冰山一角 ... ...
我打算看完《计算的本质》就去看 SICP 了 。 Clojure 的头像...... 看来是 FP 粉。
我也是因为 读《计算的本质 - 深入剖析程序和计算机》,才知道背后 有这么 牛 B 的 SICP, 作者 Tom 只是借鉴 SICP 思想而已, 然后用 Ruby 语言表达.
SICP 这本书改变了我, 让我转向了 Clojure 开发, 释放 Lisp 函数式强大的原力.
Lisp 语言里面一般都是用 partial, 函数式数据分析, 还有在线数据流机器学习, 实在是太方便了.
(def sigma
(fn [sf f a b]
(->> (range a (inc b))
(map #(f %))
(reduce sf))))
(def sum-of-number (partial sigma + (fn [n] n)))
(def sum-of-square (partial sigma + #(* % %)))
(sum-of-number 1 10) ;;=> 55
(sum-of-square 1 10) ;;=> 385
(def pi (partial sigma *))
(pi (fn [n] n) 1 3) ;;=> 6
(defn ratings->matrix [data]
(let [cardinality (-> data
(spark/map #(.product %))
(spark/reduce max)
(inc))]
(->> data
(spark/group-by #(.user %))
(spark/values)
(spark/map (to-sparse-vector cardinality))
(to-matrix))))
这是函数式圣经级别读物, 我第一次看到这部著作的时候,也直接丢掉了.
Jim Weirich 的演讲, 让我深度思考了函数式, 使得我重新读完这部书的前面四章, 被 SICP 震惊了, 发现我错了. 才知道邱奇是多么的伟大, Lisp 是多么伟大.
吃透了 SICP, 一般的程序员的功力就干不过你了. 所以它不是那么容易吃透的呀.
->
& ->>
的区别是 :
(macroexpand-1 '(-> 100 (+ 1) (+ 2) (+ 3))) ;;=> (+ (+ (+ 100 1) 2) 3)
(macroexpand-1 '(->> 100 (+ 1) (+ 2) (+ 3))) ;;=> (+ 3 (+ 2 (+ 1 100)))
为什么选择 clojure?我之前花了很大的力气装了 clisp,不过感觉它的 REPL 用起来不算太舒服,安装也比较麻烦。也有试过 scheme 感觉还不错。现在用的比较多是 elisp,平时会用来改一下 emacs 的配置。
Clojure 除了具备了 Lisp 开发的 最佳体验 (Emacs + REPL) 开发, 没有比这个开发体验更好的, 我用过如此多的语言里面.
而且 Clojure 的资源几乎是无限的, Java 资源轻易封装使用, 如我自己封装的一些 : 讯飞 Clojure 的 SDK, Hanlping, 阿里云 aliyun-oss-clj 等等.
而且 ClojureScript 函数式来写复杂前端都轻易搞定: https://github.com/chanshunli/clojurescript-study, https://github.com/clojurescript-scope-games/flappy-bird-demo 等等. 也是 Lisp 的开发体验, 甚至不需要离开编辑器就完成了复杂单页面或者游戏.
还有我用 Clojure 调用 Spark 数据分析, 机器学习等: 如 https://github.com/clojure-spark/sparkling-streaming-ml
我还用 Clojure 来写安卓 APP 收集传感器数据, 做流式数据在线学习 等,
Java 能做的, Clojure 一样能做, 而且速度快的 惊人, 曾经我认为 Ruby 是最好的语言, 但是我错了, 能够开发 Clojure 是我命运的眷顾, 让我知道 什么才是程序员的幸福
, Clojure 给我的感觉是, 优美的极点 + 无穷的强大几乎没有它干不了的事情.
@lanzhiheng ClojureScript 安装相对容易, 直接用 Brew 或者 npm 就能装好. REPL 环境现在有 Lumo 和 Planck, 启动很快, 不知道你需要什么功能, 应该是有常用功能的. ClojureScript 社区比较注重工程化的实用性, 不过也难说, 毕竟 js 生态有些坑, Lisp 社区放不下身段, 也就跟着坑了.
感谢您的推荐,我是之前装 cLisp 感觉有点折腾,要编译安装跟 homebrew 一起用才行. ClojureScript 还没了解过,说实在干了大半年前端,感觉完全跟不上前端的节奏。自从小程序这种东西出来之后这种感觉更强烈。我也就没花太多时间去折腾前端的事情了。平时就上班时间好好写样式,写 JavaScript 框架看需要,业余有时间就去搞搞 Ruby 或者看看你们所说的 Lisp。
@Peter 如果你们学习 Lambda 演算, 连 它的 鼻祖都 不知道, 那有何意义呢?
Ruby 社区很多高手, 比如 @luikore 等, 都是修炼过 SICP 的, 如果你不知道他们为什么这么厉害, 只能说你们在社区白混了.
今年的RubyConf China 2017, 都已经有三个主题是 关于函数式的了, 难道你们还要停留在学习的舒适区吗?
嗯 Lisp 的正统是 Scheme, Scheme 的正统是 Racket ...
Racket 不仅开箱即 R5RS, R6RS, R7RS... 现在还能跑在 Chez Scheme 上了, Chez Scheme 那代码库克隆下来都上 G 了咯.
小心莫走进 Clojure 或者 Common Lisp 的邪路呀!
还是这个 Elixir 更吸引 ruby 圈子吧。对比一下,没有 @变量的耦合,是不是觉得更清楚些呢?
defmodule DrawShapes do
def areas(shapes) do
for shape <- shapes do
area(shape)
end
end
def area(shape) do
module = shape.__struct__
apply(module, :area, [shape])
end
end
defmodule Circle do
defstruct radius: nil
def new(radius), do: %Circle{radius: radius}
def area(circle) do
(circle.radius * :math.pi) |> :math.pow(2)
end
end
defmodule Square do
defstruct side: nil
def new(side), do: %Square{side: side}
def area(square) do
square.side |> :math.pow(2)
end
end
shapes = [Circle.new(3), Square.new(4)]
DrawShapes.areas(shapes)
虽然这么说, 现在和业界结合比较紧密的 Lisp 方言还是腰酸 Clojure 啊. 再说 Lisp 本身不是就已经算邪路了吗 - -
是啊, Common Lisp 你一个 Lisp 搞什么 Object, Meta-Object Protocol?
你跟别人讲我用 Common Lisp 啦, 下了一个世界最快的编译器 sbcl ! 别人说好牛哦那你能 call/cc 吗? 玩不了这些花为什么不用 Java? 你就 sb 了...
讲真 Racket 的社区比 CL 更活跃, Scheme 也更纯粹简单, 装个 Racket 什么都有了, 何苦搞 CL?
Clojure 和 Racket 还算相似... 不过你干点什么事情都得找 Java 的库看 Java, 这不仅是一门语言...
Common Lisp 不是有。。。Common Lisp Object System (CLOS) 嘛。。。像 Scheme 上的 Gauche、Meroon,还有 Guile 上的 GOOPS 都可以看作是受这玩意的启发在其它语言上的实践。call/cc
是真痛。。。很多时候只能靠 handler-bind
苟活一下
@luikore Scheme 和 Racket, 是 Lisp 界的标准, 这一点不容置疑, 学透 SICP 可以完全升级一个程序员的 内功.
但 Scheme 的问题是停留在教育层面的, 虽然 Racket 尝试生产方面, 毕竟还没成功.
Scheme 和 Clojure 是很像的, 但是 Clojure 的生产效率是非常高的, 它和 Java 之间的互操作, 都是简单得让你惊奇. 而且 Ruby 底子好的人, 看 Java 代码是不难的.
Clojure 后端开发 非常成熟, ClojureScript 前端开发体验也是一流的, 而且 Clojure 在大数据和数据分析领域也是非常成熟的, 如 Storm, Cascalog, 包括 Clojure 调用 Spark 也是非常容易的.
Common Lisp 已经是混合多范式了, 虽然根植于 Lisp, 我不想用它的原因是, CLOS 不应该继承到 它的核心里面, 使得 Clisp 过度复杂.
还真是有这个问题... 主要是我对 js 生态已经熟悉了, 觉得作为低级语言被 ClojureScript 这个高级语言调用就当是平台 API 了 - -