美文网首页
clojure macro 宏的一点浅见

clojure macro 宏的一点浅见

作者: onedam | 来源:发表于2022-11-18 13:40 被阅读0次
    423c5949c3fb887f00cb38156903c94.jpg

    工作之余 站在半山腰 清风吹来, 大西北干燥的凛冽,似乎要吹进骨子里,心中升起一种印在灵魂深处的无法言说的亲切感.

    从2012年到现在, clojure 在我生命中已经陪伴了快10年了. <黑客和画家> 一书让很多人对 lisp 神向往之 . 在王垠大神的推荐下,浅尝辄止了下chez scheme,但现实中云浩的主要产品全部基于j2ee架构. 直到遇到clojure . 一颗长在java大树上的明珠 (诚然一部分同仁会对这个说法持保守意见,因为java和clojure在思想上差距巨大 一个是面向对象+设计模式, 一个是函数式编程+面向数据) , 但要掌握clojure ,你必须要经过java,要成为一个clojure执业程序员,首先必须要是一个职业java程序员 (爱好者除外)
    clojure 学习曲线并不陡峭,一些身边朋友 同事,在遇到宏的时候都感觉有点吃力,值此疫情在老家静居思过. 一点 clojure macro 记录与心得和大家分享,望指正. (clojure 官网 https://clojure.org/ 值得反复看)

    首先要理解宏的基础,为什么只有lisp系的语言才有宏? 三个字 同像性 .
    https://clojure.org/reference/reader

    Clojure is a homoiconic language, which is a fancy term describing the fact that Clojure programs are represented by Clojure data structures. This is a very important difference between Clojure (and Common Lisp) and most other programming languages - Clojure is defined in terms of the evaluation of data structures and not in terms of the syntax of character streams/files. It is quite common, and easy, for Clojure programs to manipulate, transform and produce other Clojure programs.

    代码即数据,数据即代码
    clojure 中的常用数据结构

    Symbols
    Literals
    Lists
    Vectors
    Maps
    Sets
    

    其次 编译期 运行期 这两个时期要明白.
    clojure的每一个函数(fn)都会编译成一个class类文件. 宏是一个被打了tag的函数. 在求值的时候产生的值被当做正式代码. (宏是用来产生代码的函数)

     defmacro  本身是一个fn 
     (. (var defmacro) (setMacro))
    static Keyword macroKey = Keyword.intern(null, "macro");  //打的标记 
    
    image.png

    写宏的原则
    不用宏是可以的.
    能写成函数就不要用宏(因为写宏没有写函数简单直观,容易写错,需要先在 REPL 中测试一番)
    只有不得不用时才用宏(性能要求高时比函数调用快,或者需要“代码<->数据”相互转换)
    精心设计的宏调用比函数调用更 DSL(如实现控制结构、传递 Java方法)

    以上是宏的理解关键之处. 接下来 我们再看几个难点 Macro characters
    宏中使用简写符号(语法糖)

    syntax-quote (`)(反引号)  里面才能使用 unquote  (~)  unquote-splicing (~@)
    ~  ~@ 必须要在 ` 之内. 不在其内.
    就会报;Attempting to call unbound fn: #'clojure.core/unquote
    
    `
    原原本本地直译过去,不用`,let语句不被翻译,例如: (let [datastr '{:a 1 :b 2}])
    
    ~'
    后面的变量被直接翻译过去,例如:(let [~'conn "meta"] (with-mongo ~'conn))
    
    '~
    变量名本身而非值,例如:(defn f1 [x] (println '~x ":"  ~x))  (let [a 10] (f1  a)) ;; a:10
    
    ~@
    表示后面的symbol or form is list
    
    Clojure ' `区别在于syntax-quote (`)会进行symbol的解析 (全限定名)
    user=> '(foo bar)
    (foo bar)
    user=> `(foo bar)
    (user/foo user/bar)
    
    syntax-quote 将symbol解析成为fully-qulified symbol,所谓fully-qulified symbol 
    就是形如namespace/name或fully.qualified.Classname 
    如果是symbol是非名称空间限定的(non-namespace-qualified)且以#符号结尾,
    会解析成为name_uniqueid的形式比如x_123.
    注意:
    syntaxQuote 经过一系列运算后,最后还是转化为了 quote 
    static Object syntaxQuote(Object form) {
    return ret = RT.list(Compiler.QUOTE, sym);
    }
    
    ~ ~@ 必须在 `里面
    `~'a 
    ~'idx  ;不在 syntax-quote中使用 则会报错.
    `(+ a ~'idx)  ;(clojure.core/+ cfenxi.core-test/a idx)
    
    '~x  显示变量名,即a
    ~x 解析为变量值,即a的值 10  
    

    一个递归查看 字符串 数据 与 代码关系的代码

    (ns cfenxi.core-test
     (:require [clojure.test :refer :all]
               [cfenxi.core :refer :all]
               [clojure.walk :as w])
     (:import (clojure.lang Compiler$C))
     )
    (defn study-read
     "Lisp reader 的时候,会把字符 根据规则解析成 data 具体类型是 java 定义的.
     Symbol PersistentList String MapEntry PersistentArrayMap
     Keyword PersistentList
     "
     [str]
     (let [r (read-string str)]
      (w/prewalk (fn [x] (prn x (type x)) x) r)
      ;(w/prewalk-demo r)
      )
     )
    
    (study-read "(+ 3 2)")
    (study-read "(fn [x] (do {:a x}))")
    
    Loading test/cfenxi/core_test.clj... 
    (+ 3 2) clojure.lang.PersistentList
    + clojure.lang.Symbol
    3 java.lang.Long
    2 java.lang.Long
    (fn [x] (do {:a x})) clojure.lang.PersistentList
    fn clojure.lang.Symbol
    [x] clojure.lang.PersistentVector
    x clojure.lang.Symbol
    (do {:a x}) clojure.lang.PersistentList
    do clojure.lang.Symbol
    {:a x} clojure.lang.PersistentArrayMap
    [:a x] clojure.lang.MapEntry
    :a clojure.lang.Keyword
    x clojure.lang.Symbol
    
    clojure2 miss chang

    相关文章

      网友评论

          本文标题:clojure macro 宏的一点浅见

          本文链接:https://www.haomeiwen.com/subject/muwmxdtx.html