<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>

                ??一站式輕松地調用各大LLM模型接口,支持GPT4、智譜、豆包、星火、月之暗面及文生圖、文生視頻 廣告
                ## 函數定義 `defn` 宏用來定義一個函數。它的參數包括一個函數名字,一個可選的注釋字符串,參數列表,然后一個方法體。而函數的返回值則是方法體里面最后一個表達式的值。所有的函數都會返回一個值, 只是有的返回的值是nil。看例子: ``` (defn parting "returns a String parting" [name] (str "Goodbye, " name)) ; concatenation (println (parting "Mark")) ; -> Goodbye, Mark ``` 函數必須先定義再使用。有時候可能做不到, 比如兩個方法項目調用,clojure采用了和C語言里面類似的做法: declare, 看例子: ``` (declare <em>function-names</em>) ``` 通過宏 `defn-` 定義的函數是私有的. 這意味著它們只在定義它們的名字空間里面可見. 其它一些類似定義私有函數/宏的還有: `defmacro-` 和 `defstruct-` (在 `clojure.contrib.def` 里面)。 函數的參數個數可以是不定的。可選的那些參數必須放在最后面(這一點跟其它語言是一樣的), 你可以通過加個&符號把它們收集到一個list里面去Functions can take a variable number of parameters. Optional parameters must appear at the end. They are gathered into a list by adding an ampersand and a name for the list at the end of the parameter list. ``` (defn power [base & exponents] ; Using java.lang.Math static method pow. (reduce #(Math/pow %1 %2) base exponents)) (power 2 3 4) ; 2 to the 3rd = 8; 8 to the 4th = 4096 ``` 函數定義可以包含多個參數列表以及對應的方法體。每個參數列表必須包含不同個數的參數。這通常用來給一些參數指定默認值。看例子: ``` (defn parting "returns a String parting in a given language" ([] (parting "World")) ([name] (parting name "en")) ([name language] ; condp is similar to a case statement in other languages. ; It is described in more detail later. ; It is used here to take different actions based on whether the ; parameter "language" is set to "en", "es" or something else. (condp = language "en" (str "Goodbye, " name) "es" (str "Adios, " name) (throw (IllegalArgumentException. (str "unsupported language " language)))))) (println (parting)) ; -> Goodbye, World (println (parting "Mark")) ; -> Goodbye, Mark (println (parting "Mark" "es")) ; -> Adios, Mark (println (parting "Mark", "xy")) ; -> java.lang.IllegalArgumentException: unsupported language xy ``` 匿名函數是沒有名字的。他們通常被當作參數傳遞給其他有名函數(相對于匿名函數)。匿名函數對于那些只在一個地方使用的函數比較有用。下面是定義匿名函數的兩種方法: ``` (def years [1940 1944 1961 1985 1987]) (filter (fn [year] (even? year)) years) ; long way w/ named arguments -> (1940 1944) (filter #(even? %) years) ; short way where % refers to the argument ``` 通過 `fn` 定義的匿名函數可以包含任意個數的表達式; 而通過 `#(...)` , 定義的匿名函數則只能包含一個表達式,如果你想包含多個表達式,那么把它用 `do` 包起來。如果只有一個參數, 那么你可以通過 `%` 來引用它; 如果有多個參數, 那么可以通過 `%1` , `%2` 等等來引用。 看例子: ``` (defn pair-test [test-fn n1 n2] (if (test-fn n1 n2) "pass" "fail")) ; Use a test-fn that determines whether ; the sum of its two arguments is an even number. (println (pair-test #(even? (+ %1 %2)) 3 5)) ; -> pass ``` Java里面的方法可以根據參數的類型來進行重載。而Clojure里面則只能根據參數的個數來進行重載。不過Clojure里面的multimethods技術可以實現任意 類型的重載。 宏 `defmulti` 和 `defmethod` 經常被用在一起來定義 multimethod. 宏 `defmulti` 的參數包括一個方法名以及一個dispatch函數,這個dispatch函數的返回值會被用來選擇到底調用哪個重載的函數。宏 `defmethod` 的參數則包括方法名,dispatch的值, 參數列表以及方法體。一個特殊的dispatch值 `:default` 是用來表示默認情況的 — 即如果其它的dispatch值都不匹配的話,那么就調用這個方法。 `defmethod` 多定義的名字一樣的方法,它們的參數個數必須一樣。傳給multimethod的參數會傳給dipatch函數的。 下面是一個用multimethod來實現基于參數的類型來進行重載的例子: ``` (defmulti what-am-i class) ; class is the dispatch function (defmethod what-am-i Number [arg] (println arg "is a Number")) (defmethod what-am-i String [arg] (println arg "is a String")) (defmethod what-am-i :default [arg] (println arg "is something else")) (what-am-i 19) ; -> 19 is a Number (what-am-i "Hello") ; -> Hello is a String (what-am-i true) ; -> true is something else ``` 因為dispatch函數可以是任意一個函數,所以你也可以寫你自己的dispatch函數。比如一個自定義的dispatch函數可以會根據一個東西的尺寸大小來返回 `:small` , `:medium` 以及 `:large` 。然后對應每種尺寸有一個方法。 下劃線可以用來作為參數占位符 ?– 如果你不要使用這個參數的話。這個特性在回調函數里面比較有用, 因為回調函數的設計者通常想把盡可能多的信息給你, 而你通常可能只需要其中的一部分。看例子: ``` (defn callback1 [n1 n2 n3] (+ n1 n2 n3)) ; uses all three arguments (defn callback2 [n1 _ n3] (+ n1 n3)) ; only uses 1st & 3rd arguments (defn caller [callback value] (callback (+ value 1) (+ value 2) (+ value 3))) (caller callback1 10) ; 11 + 12 + 13 -> 36 (caller callback2 10) ; 11 + 13 -> 24 ``` `complement` 函數接受一個函數作為參數,如果這個參數返回值是true, 那么它就返回false, 相當于一個取反的操作。看例子: ``` (defn teenager? [age] (and (>= age 13) (< age 20))) (def non-teen? (complement teenager?)) (println (non-teen? 47)) ; -> true ``` `comp` 把任意多個函數組合成一個,前面一個函數的返回值作為后面一個函數的參數。 **調用的順序是從右到左(注意不是從左到右)** 看例子: ``` (defn times2 [n] (* n 2)) (defn minus3 [n] (- n 3)) ; Note the use of def instead of defn because comp returns ; a function that is then bound to "my-composition". (def my-composition (comp minus3 times2)) (my-composition 4) ; 4*2 - 3 -> 5 ``` `partial` 函數創建一個新的函數 — 通過給舊的函數制定一個初始值, 然后再調用原來的函數。比如 `*` 是一個可以接受多個參數的函數,它的作用就是計算它們的乘積,如果我們想要一個新的函數,使的返回結果始終是乘積的2倍,我們可以這樣做: ``` ; Note the use of def instead of defn because partial returns ; a function that is then bound to "times2". (def times2 (partial * 2)) (times2 3 4) ; 2 * 3 * 4 -> 24 ``` 下面是一個使用 `map` 和 `partial` 的有趣的例子. ``` (defn- polynomial "computes the value of a polynomial with the given coefficients for a given value x" [coefs x] ; For example, if coefs contains 3 values then exponents is (2 1 0). (let [exponents (reverse (range (count coefs)))] ; Multiply each coefficient by x raised to the corresponding exponent ; and sum those results. ; coefs go into %1 and exponents go into %2. (apply + (map #(* %1 (Math/pow x %2)) coefs exponents)))) (defn- derivative "computes the value of the derivative of a polynomial with the given coefficients for a given value x" [coefs x] ; The coefficients of the derivative function are obtained by ; multiplying all but the last coefficient by its corresponding exponent. ; The extra exponent will be ignored. (let [exponents (reverse (range (count coefs))) derivative-coefs (map #(* %1 %2) (butlast coefs) exponents)] (polynomial derivative-coefs x))) (def f (partial polynomial [2 1 3])) ; 2x^2 + x + 3 (def f-prime (partial derivative [2 1 3])) ; 4x + 1 (println "f(2) =" (f 2)) ; -> 13.0 (println "f'(2) =" (f-prime 2)) ; -> 9.0 ``` 下面是另外一種做法 (Francesco Strino建議的). %1 = a, %2 = b, result is ax + b %1 = ax + b, %2 = c, result is (ax + b)x + c = ax^2 + bx + c ``` (defn- polynomial "computes the value of a polynomial with the given coefficients for a given value x" [coefs x] (reduce #(+ (* x %1) %2) coefs)) ``` `memoize` 函數接受一個參數,它的作用就是給原來的函數加一個緩存,所以如果同樣的參數被調用了兩次, 那么它就直接從緩存里面返回緩存了的結果,以提高效率, 但是當然它會需要更多的內存。(其實也只有函數式編程里面能用這個技術, 因為函數沒有side-effect, 多次調用的結果保證是一樣的) `time` 宏可以看成一個wrapper函數, 它會打印被它包起來的函數的執行時間,并且返回這個函數的返回值。看下面例子里面是怎么用的。 下面的例子演示在多項式的的計算里面使用memoize: ``` ; Note the use of def instead of defn because memoize returns ; a function that is then bound to "memo-f". (def memo-f (memoize f)) (println "priming call") (time (f 2)) (println "without memoization") ; Note the use of an underscore for the binding that isn't used. (dotimes [_ 3] (time (f 2))) (println "with memoization") (dotimes [_ 3] (time (memo-f 2))) ``` 上面代碼的輸出是這樣的: ``` priming call "Elapsed time: 4.128 msecs" without memoization "Elapsed time: 0.172 msecs" "Elapsed time: 0.365 msecs" "Elapsed time: 0.19 msecs" with memoization "Elapsed time: 0.241 msecs" "Elapsed time: 0.033 msecs" "Elapsed time: 0.019 msecs" ``` 從上面的輸出我們可以看到好幾個東西。首先第一個方法調用比其它的都要長很多。– 其實這和用不用memonize沒有什么關系。第一個memoize調用所花的時間也要比其他memoize調用花的時間要長, 因為要操作緩存,其它的memoize調用就要快很多了。
                  <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>

                              哎呀哎呀视频在线观看