<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                ## 宏 宏是用來給語言添加新的結構,新的元素的。它們是一些在讀入期(而不是編譯期)就會實際代碼替換的一個機制。 對于函數來說,它們的所有的參數都會被evaluate的, 而宏則會自動判斷哪些參數需要evaluate。 這對于實現像 `(if _condition_ _then-expr_ _else-expr_)` 這樣的結構是非常重要的。 如果 condition 是 `true` , 那么只有 "then" 表達式需要被evaluated. 如果條件是 `false` , 那么只有 "else" 表達式應該被 evaluated. 這意味著 `if` 不能被實現成一個函數 (它其實也不是宏, 而是一個special form)。其它一些因為這個原因而必須要實現成宏的包括 `and` 和 `or` 因為它們需要實現 "short-circuit"屬性。 要想知道一個東西到底是函數還是宏, 可以在REPL里面輸入 `(doc _name_)` 或者查看它的元數據。如果是一個宏的話,那么它的元數據里面包含一個 `:macro` key, 并且它的值為 `true` 。 比如,我們要看看 `and` , 是不是宏, 在REPL里面輸入下面的命令: ``` ((meta (var and)) :macro) ; long way -> true (^#'and :macro) ; short way -> true ``` 讓我們通過一些例子來看看如何編寫并且使用宏。假設我們代碼里面很多地方要對一個數字進行判斷,通過判斷它是接近0, 是正的, 是負的來執行不同的邏輯;我們又不想這種判斷的代碼到處重復,那么這種情況下我們就可以使用宏了。我們使用 `defmacro` 宏來定義一個宏。 ``` (defmacro around-zero [number negative-expr zero-expr positive-expr] `(let [number# ~number] ; so number is only evaluated once (cond (< (Math/abs number#) 1e-15) ~zero-expr (pos? number#) ~positive-expr true ~negative-expr))) ``` Clojure的reader會把所有調用around-aero的地方全部換成defmacro這個方法體里面的具體代碼。我們在這里使用let是為了性能,因為這個傳進來的number是一個表達式而不是一個簡單的值, 而且被cond語句里面使用了兩次。自動產生的變量number#是為了產生一個不會和用戶指定的其它binding沖突的一個名字。這使得我們可以創建 [hygienic macros](http://en.wikipedia.org/wiki/Hygienic_macros) . 宏定義開始的時候的那個反引號 (也稱為語法引號) 防止宏體內的任何一個表達式被evaluate -- 除非你顯示地轉義了。這意味著宏體里面的代碼會原封不動地替換到使用這個宏的所有的地方 -- 除了以波浪號開始的那些表達式。 ( `number` , `zero-expr` , `positive-expr` 和 `negative-expr` ). 當一個名字前面被加了一個波浪號,并且還在反引號里面,它的值會被替換的。如果這個名字代表的是一個序列,那么我們可以用 `~@` 這個語法來替換序列里面的某個具體元素。 下面是兩個使用這個宏的例子:(輸出都應該是 " `+` "). ``` (around-zero 0.1 (println "-") (println "0") (println "+")) (println (around-zero 0.1 "-" "0" "+")) ; same thing ``` 如果對于每種條件執行多于一個表達式, 那么用do把他們包起來。看下面例子: ``` (around-zero 0.1 (do (log "really cold!") (println "-")) (println "0") (println "+")) ``` 為了驗證這個宏是否被正確展開, 在REPL里面輸入這個: ``` (macroexpand-1 '(around-zero 0.1 (println "-") (println "0") (println "+"))) ``` 它會輸出下面這個(為了容易看懂, 我加了縮進) ``` (clojure.core/let [number__3382__auto__ 0.1] (clojure.core/cond (clojure.core/< (Math/abs number__3382__auto__) 1.0E-15) (println "0") (clojure.core/pos? number__3382__auto__) (println "+") true (println "-"))) ``` 下面是一個使用這個宏來返回一個描述輸入數字的屬性的字符串的函數。 ``` (defn number-category [number] (around-zero number "negative" "zero" "positive")) ``` 下面是一些示例用法: ``` (println (number-category -0.1)) ; -> negative (println (number-category 0)) ; -> zero (println (number-category 0.1)) ; -> positive ``` 因為宏不會 evaluate 它們的參數, 所以你可以在宏體里面寫一個對函數的參數調用. 函數定義不能這么做,相反只能用匿名函數把它們包起來。 下面是一個接受兩個參數的宏。第一個是一個接受一個參數的函數, 這個參數是一個弧度, 如果它是一個三角函數sin, cos。第二個參數是一個弧度。如果這個被寫成一個函數而不是一個 宏的話, 那么我們需要傳遞一個 `#(Math/sin %)` 而不是簡單的 `Math/sin` 作為參數。注意 那些后面的#符號, 它會產生一個唯一的、不沖突的本地binding。 `#` 和 `~` 都必須在反引號引著的列表里面才能使用。 ``` (defmacro trig-y-category [fn degrees] `(let [radians# (Math/toRadians ~degrees) result# (~fn radians#)] (number-category result#))) ``` 讓我們試一下。下面代碼的期望輸出應該是 "zero", "positive", "zero" 和 "negative". ``` (doseq [angle (range 0 360 90)] ; 0, 90, 180 and 270 (println (trig-y-category Math/sin angle))) ``` 宏的名字不能作為參數傳遞給函數。比如一個宏的名字比如 `and` 不能作為參數傳遞給 `reduce` 函數。一個繞過的方法是定義一個匿名函數把這個宏包起來。比如 `(fn [x y] (and x y))` 或者 `#(and %1 %2)` . 宏會在這個讀入期在這個匿名函數體內解開。當這個函數被傳遞給函數比如 `reduce` , 傳遞的是函數而不是宏。 宏的調用是在讀入期處理的。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看