From 9842c8859b03e34f0ba09a3e6885218d67a3862d Mon Sep 17 00:00:00 2001 From: Boris Verkhovskiy Date: Thu, 16 May 2024 03:23:02 -0600 Subject: Correct URLs --- zh-cn/clojure-macro-cn.html.markdown | 150 ---------------------------------- zh-cn/clojure-macros-cn.html.markdown | 150 ++++++++++++++++++++++++++++++++++ 2 files changed, 150 insertions(+), 150 deletions(-) delete mode 100644 zh-cn/clojure-macro-cn.html.markdown create mode 100644 zh-cn/clojure-macros-cn.html.markdown (limited to 'zh-cn') diff --git a/zh-cn/clojure-macro-cn.html.markdown b/zh-cn/clojure-macro-cn.html.markdown deleted file mode 100644 index 85b966e9..00000000 --- a/zh-cn/clojure-macro-cn.html.markdown +++ /dev/null @@ -1,150 +0,0 @@ ---- -language: "clojure macros" -filename: learnclojuremacros-zh.clj -contributors: - - ["Adam Bard", "http://adambard.com/"] -translators: - - ["Jakukyo Friel", "http://weakish.github.io"] -lang: zh-cn ---- - -和所有Lisp一样,Clojure内在的[同构性](https://en.wikipedia.org/wiki/Homoiconic)使得你可以穷尽语言的特性,编写生成代码的子过程——“宏”。宏是一种按需调制语言的强大方式。 - -小心!可以用函数完成的事用宏去实现可不是什么好事。你应该仅在需要控制参数是否或者何时eval的时候使用宏。 - -你应该熟悉Clojure.确保你了解[Y分钟学Clojure](http://learnxinyminutes.com/docs/zh-cn/clojure-cn/)中的所有内容。 - -```clojure -;; 使用defmacro定义宏。宏应该输出一个可以作为clojure代码演算的列表。 -;; -;; 以下宏的效果和直接写(reverse "Hello World")一致。 - -(defmacro my-first-macro [] - (list reverse "Hello World")) - -;; 使用macroexpand或macroexpand-1查看宏的结果。 -;; -;; 注意,调用需要引用。 -(macroexpand '(my-first-macro)) -;; -> (# "Hello World") - -;; 你可以直接eval macroexpand的结果 -(eval (macroexpand '(my-first-macro))) -; -> (\d \l \o \r \W \space \o \l \l \e \H) - -;; 不过一般使用以下形式,更简短,更像函数: -(my-first-macro) ; -> (\d \l \o \r \W \space \o \l \l \e \H) - -;; 创建宏的时候可以使用更简短的引用形式来创建列表 -(defmacro my-first-quoted-macro [] - '(reverse "Hello World")) - -(macroexpand '(my-first-quoted-macro)) -;; -> (reverse "Hello World") -;; 注意reverse不再是一个函数对象,而是一个符号。 - -;; 宏可以传入参数。 -(defmacro inc2 [arg] - (list + 2 arg)) - -(inc2 2) ; -> 4 - -;; 不过,如果你尝试配合使用引用列表,会导致错误, -;; 因为参数也会被引用。 -;; 为了避免这个问题,clojure提供了引用宏的另一种方式:` -;; 在`之内,你可以使用~获得外圈作用域的变量。 -(defmacro inc2-quoted [arg] - `(+ 2 ~arg)) - -(inc2-quoted 2) - -;; 你可以使用通常的析构参数。用~@展开列表中的变量。 -(defmacro unless [arg & body] - `(if (not ~arg) - (do ~@body))) ; 别忘了 do! - -(macroexpand '(unless true (reverse "Hello World"))) - -;; -> -;; (if (clojure.core/not true) (do (reverse "Hello World"))) - -;; 当第一个参数为假时,(unless)会演算、返回主体。 -;; 否则返回nil。 - -(unless true "Hello") ; -> nil -(unless false "Hello") ; -> "Hello" - -;; 需要小心,宏会搞乱你的变量 -(defmacro define-x [] - '(do - (def x 2) - (list x))) - -(def x 4) -(define-x) ; -> (2) -(list x) ; -> (2) - -;; 使用gensym来获得独有的标识符 -(gensym 'x) ; -> x1281 (or some such thing) - -(defmacro define-x-safely [] - (let [sym (gensym 'x)] - `(do - (def ~sym 2) - (list ~sym)))) - -(def x 4) -(define-x-safely) ; -> (2) -(list x) ; -> (4) - -;; 你可以在 ` 中使用 # 为每个符号自动生成gensym -(defmacro define-x-hygenically [] - `(do - (def x# 2) - (list x#))) - -(def x 4) -(define-x-hygenically) ; -> (2) -(list x) ; -> (4) - -;; 通常会配合宏使用帮助函数。 -;; 让我们创建一些帮助函数来支持(无聊的)算术语法: - -(declare inline-2-helper) -(defn clean-arg [arg] - (if (seq? arg) - (inline-2-helper arg) - arg)) - -(defn apply-arg - "Given args [x (+ y)], return (+ x y)" - [val [op arg]] - (list op val (clean-arg arg))) - -(defn inline-2-helper - [[arg1 & ops-and-args]] - (let [ops (partition 2 ops-and-args)] - (reduce apply-arg (clean-arg arg1) ops))) - -;; 在创建宏前,我们可以先测试 -(inline-2-helper '(a + (b - 2) - (c * 5))) ; -> (- (+ a (- b 2)) (* c 5)) - -; 然而,如果我们希望它在编译期执行,就需要创建宏 -(defmacro inline-2 [form] - (inline-2-helper form)) - -(macroexpand '(inline-2 (1 + (3 / 2) - (1 / 2) + 1))) -; -> (+ (- (+ 1 (/ 3 2)) (/ 1 2)) 1) - -(inline-2 (1 + (3 / 2) - (1 / 2) + 1)) -; -> 3 (事实上,结果是3N, 因为数字被转化为带/的有理分数) -``` - -## 扩展阅读 - -[Clojure for the Brave and True](http://www.braveclojure.com/) -[系列的编写宏](http://www.braveclojure.com/writing-macros/) - -[官方文档](http://clojure.org/macros) - -[何时使用宏?](https://lispcast.com/when-to-use-a-macro/) diff --git a/zh-cn/clojure-macros-cn.html.markdown b/zh-cn/clojure-macros-cn.html.markdown new file mode 100644 index 00000000..85b966e9 --- /dev/null +++ b/zh-cn/clojure-macros-cn.html.markdown @@ -0,0 +1,150 @@ +--- +language: "clojure macros" +filename: learnclojuremacros-zh.clj +contributors: + - ["Adam Bard", "http://adambard.com/"] +translators: + - ["Jakukyo Friel", "http://weakish.github.io"] +lang: zh-cn +--- + +和所有Lisp一样,Clojure内在的[同构性](https://en.wikipedia.org/wiki/Homoiconic)使得你可以穷尽语言的特性,编写生成代码的子过程——“宏”。宏是一种按需调制语言的强大方式。 + +小心!可以用函数完成的事用宏去实现可不是什么好事。你应该仅在需要控制参数是否或者何时eval的时候使用宏。 + +你应该熟悉Clojure.确保你了解[Y分钟学Clojure](http://learnxinyminutes.com/docs/zh-cn/clojure-cn/)中的所有内容。 + +```clojure +;; 使用defmacro定义宏。宏应该输出一个可以作为clojure代码演算的列表。 +;; +;; 以下宏的效果和直接写(reverse "Hello World")一致。 + +(defmacro my-first-macro [] + (list reverse "Hello World")) + +;; 使用macroexpand或macroexpand-1查看宏的结果。 +;; +;; 注意,调用需要引用。 +(macroexpand '(my-first-macro)) +;; -> (# "Hello World") + +;; 你可以直接eval macroexpand的结果 +(eval (macroexpand '(my-first-macro))) +; -> (\d \l \o \r \W \space \o \l \l \e \H) + +;; 不过一般使用以下形式,更简短,更像函数: +(my-first-macro) ; -> (\d \l \o \r \W \space \o \l \l \e \H) + +;; 创建宏的时候可以使用更简短的引用形式来创建列表 +(defmacro my-first-quoted-macro [] + '(reverse "Hello World")) + +(macroexpand '(my-first-quoted-macro)) +;; -> (reverse "Hello World") +;; 注意reverse不再是一个函数对象,而是一个符号。 + +;; 宏可以传入参数。 +(defmacro inc2 [arg] + (list + 2 arg)) + +(inc2 2) ; -> 4 + +;; 不过,如果你尝试配合使用引用列表,会导致错误, +;; 因为参数也会被引用。 +;; 为了避免这个问题,clojure提供了引用宏的另一种方式:` +;; 在`之内,你可以使用~获得外圈作用域的变量。 +(defmacro inc2-quoted [arg] + `(+ 2 ~arg)) + +(inc2-quoted 2) + +;; 你可以使用通常的析构参数。用~@展开列表中的变量。 +(defmacro unless [arg & body] + `(if (not ~arg) + (do ~@body))) ; 别忘了 do! + +(macroexpand '(unless true (reverse "Hello World"))) + +;; -> +;; (if (clojure.core/not true) (do (reverse "Hello World"))) + +;; 当第一个参数为假时,(unless)会演算、返回主体。 +;; 否则返回nil。 + +(unless true "Hello") ; -> nil +(unless false "Hello") ; -> "Hello" + +;; 需要小心,宏会搞乱你的变量 +(defmacro define-x [] + '(do + (def x 2) + (list x))) + +(def x 4) +(define-x) ; -> (2) +(list x) ; -> (2) + +;; 使用gensym来获得独有的标识符 +(gensym 'x) ; -> x1281 (or some such thing) + +(defmacro define-x-safely [] + (let [sym (gensym 'x)] + `(do + (def ~sym 2) + (list ~sym)))) + +(def x 4) +(define-x-safely) ; -> (2) +(list x) ; -> (4) + +;; 你可以在 ` 中使用 # 为每个符号自动生成gensym +(defmacro define-x-hygenically [] + `(do + (def x# 2) + (list x#))) + +(def x 4) +(define-x-hygenically) ; -> (2) +(list x) ; -> (4) + +;; 通常会配合宏使用帮助函数。 +;; 让我们创建一些帮助函数来支持(无聊的)算术语法: + +(declare inline-2-helper) +(defn clean-arg [arg] + (if (seq? arg) + (inline-2-helper arg) + arg)) + +(defn apply-arg + "Given args [x (+ y)], return (+ x y)" + [val [op arg]] + (list op val (clean-arg arg))) + +(defn inline-2-helper + [[arg1 & ops-and-args]] + (let [ops (partition 2 ops-and-args)] + (reduce apply-arg (clean-arg arg1) ops))) + +;; 在创建宏前,我们可以先测试 +(inline-2-helper '(a + (b - 2) - (c * 5))) ; -> (- (+ a (- b 2)) (* c 5)) + +; 然而,如果我们希望它在编译期执行,就需要创建宏 +(defmacro inline-2 [form] + (inline-2-helper form)) + +(macroexpand '(inline-2 (1 + (3 / 2) - (1 / 2) + 1))) +; -> (+ (- (+ 1 (/ 3 2)) (/ 1 2)) 1) + +(inline-2 (1 + (3 / 2) - (1 / 2) + 1)) +; -> 3 (事实上,结果是3N, 因为数字被转化为带/的有理分数) +``` + +## 扩展阅读 + +[Clojure for the Brave and True](http://www.braveclojure.com/) +[系列的编写宏](http://www.braveclojure.com/writing-macros/) + +[官方文档](http://clojure.org/macros) + +[何时使用宏?](https://lispcast.com/when-to-use-a-macro/) -- cgit v1.2.3