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

简介:

前言

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

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实现上述代码将会如此地丑陋

(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函数

;; 定义
(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宏

;; 定义
(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让我们可以灵活扩展语言特性,真是越用越酸爽啊!
尊重原创,转载请注明来自:http://www.cnblogs.com/fsjohnhuang/p/7103601.html ^_^肥仔John

如果您觉得本文的内容有趣就扫一下吧!捐赠互勉!

本文转自^_^肥仔John博客园博客,原文链接:http://www.cnblogs.com/fsjohnhuang/p/7103601.html,如需转载请自行联系原作者

 

相关文章
|
21天前
|
JavaScript 前端开发 开发者
call 方法和 apply 方法的区别是什么?
【10月更文挑战第26天】`call` 方法和 `apply` 方法的主要区别在于参数传递方式和使用场景。开发者可以根据具体的函数参数情况和代码的可读性、简洁性要求来选择使用 `call` 方法还是 `apply` 方法,以实现更高效、更易读的JavaScript代码。
28 2
|
2月前
|
JavaScript 前端开发
js 中call()和apply()
js 中call()和apply()
29 1
|
Python
apply函数的用法
apply是pandas处理数据经常用到的函数。我们可以用DataFrame的apply函数实现对多列、多行的操作。可通过axis设置参数,设为1是对列进行操作,参数axis设为0是对行操作。apply经常跟lambda一起使用,非常方便,大大提高了效率。
153 0
|
7月前
|
JavaScript 前端开发
call函数和apply函数的区别
call函数和apply函数的区别
53 0
|
前端开发 JavaScript Java
函数防抖节流原理及封装+闭包+call/apply/bind
函数防抖节流原理及封装+闭包+call/apply/bind
93 0
手写call-apply-bind以及了解柯里化
手写call-apply-bind以及了解柯里化
|
XML Java Android开发
Kotlin作用域函数let、with、run、apply、also
Kotlin作用域函数let、with、run、apply、also
87 0
|
存储 Python
Python中函数参数传递方法*args, **kwargs,还有其他
本文将讨论Python的函数参数。我们将了解*args和**kwargs,/和*的都是什么,虽然这个问题是一个基本的python问题,但是在我们写代码时会经常遇到,比如timm中就大量使用了这样的参数传递方式。
290 0
|
Kotlin
Kotlin 作用域函数之let、with、run、also、apply的使用笔记
`Kotlin` 标准库包含几个函数,目的是在对象的上下文中执行代码块。**当对一个对象调用这样的函数并提供一个 `lambda` 表达式时,会形成一个临时作用域。在此作用域中,可以访问该对象而无需其名称。这些函数称为作用域函数**。共有以下五种:`let、run、with、apply 以及 also`。
220 0
|
程序员 Go
Go 函数详解 func 匿名函数 闭包
函数是任何一门编程语言最重要的组成部分之一。函数简单理解是一段代码的封装:把一段逻辑抽象出来封装到一个函数中,给他取个名字,每次需要的时候调用这个函数即可。使用函数能够让代码更清晰,更简洁。
289 0
Go 函数详解 func 匿名函数 闭包