zoukankan      html  css  js  c++  java
  • (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

  • 相关阅读:
    ef mysql
    mvc RedirectToAction、mobile 重定向地址栏未改变
    避免复制引用程序集的XML文件
    端口扫描工具
    Python简单全双工聊天器
    Python半双工聊天程序
    Python简单服务器程序
    python+scrapy爬取亚马逊手机商品
    python+scrapy爬取知乎日报全站文章
    简单直接排序
  • 原文地址:https://www.cnblogs.com/fsjohnhuang/p/7103601.html
Copyright © 2011-2022 走看看