首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >(cljs/run-at (JSVM. :all) "一起实现柯里化")

(cljs/run-at (JSVM. :all) "一起实现柯里化")

作者头像
^_^肥仔John
发布2018-01-18 17:51:45
发布2018-01-18 17:51:45
73900
代码可运行
举报
运行总次数:0
代码可运行

前言

 习惯了Ramda.js就会潜意识地认为函数均已柯里化,然后就可以随心所欲的用函数生成函数,或者使用compose组合多个函数来生成一个新函数。如下

代码语言:javascript
代码运行次数:0
运行
复制
const f = a => b => a + b
const g = c => d => c - d
const compose = f => g => x => f(g(x))

const add1 = f(1)
add1(2) // 返回3

const addThenMinus = compose(g(2), f(1))
addThenMinus(3) // 返回-2

 ES6的arrow function让我们轻易写出柯里化的函数(当然使用Ramda.js会更轻松),若换成ES5就蛋痛很多了。而不幸的是cljs采纳和js一样能够接受可变参数的函数特性,这使得其必须抛弃如haskell函数自动柯里化的特性。若用cljs实现上述代码将会如此地丑陋

代码语言:javascript
代码运行次数:0
运行
复制
(defn f [a]
    (fn [b] (+ a b)))
(defn g [c]
    (fn [d] (- c d)))

(def add1 (f 1))

 那么要如何才能在cljs中优美地实现柯里化呢?答案是两步走:

  1. 实现Ramda.js中R.curry函数的cljs版
  2. 借助curry函数实现macro

实现curry函数

代码语言:javascript
代码运行次数:0
运行
复制
;; 定义
(defn curry
  [f n & args]
  (fn [& more]
    (let [a (vec (concat args more))]
      (if (> n (count a))
        (apply curry (reduce conj [f n] a))
        (apply f (take n a))))))

;; 使用
(defn f [a b]
    (+ a b))
(def fc (curry f 2))
(def add1 (fc 1))

实现defnc宏

代码语言:javascript
代码运行次数:0
运行
复制
;; 定义
(defmacro defnc [name args & body]
  {:pre [(not-any? #{\&} args)]}
  (let [n (count args)]
  `(def ~name
     (curry
       (fn ~args ~@body)
       ~n))))

;; 使用
(defnc f [a b]
    (+ a b))
(def add1 (f 1))

总结

 cljs中的macro让我们可以灵活扩展语言特性,真是越用越酸爽啊!

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2017-07-02 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 实现curry函数
  • 实现defnc宏
  • 总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档