Jak utworzyć wartość domyślną dla argumentu funkcji w Clojure

Przychodzę z tym:

(defn string->integer [str & [base]]
  (Integer/parseInt str (if (nil? base) 10 base)))

(string->integer "10")
(string->integer "FF" 16)
Ale to musi być lepszy sposób.
Author: jcubic, 2010-07-09

5 answers

Funkcja może mieć wiele podpisów, jeśli podpisy różnią się arytmetyką. Możesz użyć tego do podania wartości domyślnych.

(defn string->integer 
  ([s] (string->integer s 10))
  ([s base] (Integer/parseInt s base)))

Zauważ, że zakładając, że false i nil są uważane za nie wartości, (if (nil? base) 10 base) można skrócić do (if base base 10) lub dalej do (or base 10).

 145
Author: Brian Carper,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-07-08 22:10:18

Od Clojure 1.2 [ref można także destrukcję argumentów rest jako mapę. Pozwala to na nazwanie i podanie domyślnych argumentów funkcji:

(defn string->integer [s & {:keys [base] :or {base 10}}]
    (Integer/parseInt s base))

Teraz możesz zadzwonić

(string->integer "11")
=> 11

Lub

(string->integer "11" :base 8)
=> 9

Możesz zobaczyć to w akcji tutaj: https://github.com/Raynes/clavatar/blob/master/src/clavatar/core.clj (na przykład)

 141
Author: Matthew Gilliard,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-12-28 20:49:16

To rozwiązanie jest bliższe duchowi oryginalnego rozwiązania , ale nieznacznie czystsze

(defn string->integer [str & [base]]
  (Integer/parseInt str (or base 10)))

A podobny wzór który może być przydatny or w połączeniu z let

(defn string->integer [str & [base]]
  (let [base (or base 10)]
    (Integer/parseInt str base)))

Podczas gdy w tym przypadku jest to bardziej szczegółowe, może być przydatne, jeśli chcesz mieć wartości domyślne zależne od innych wartości wejściowych . Na przykład rozważmy następującą funkcję:

(defn exemplar [a & [b c]]
  (let [b (or b 5)
        c (or c (* 7 b))]
    ;; or whatever yer actual code might be...
    (println a b c)))

(exemplar 3) => 3 5 35

To podejście można łatwo rozszerzyć o pracę z nazwanymi argumentami (jak w M. Rozwiązanie gilliara) również:

(defn exemplar [a & {:keys [b c]}]
  (let [b (or b 5)
        c (or c (* 7 b))]
    (println a b c)))

Lub używając jeszcze więcej fuzji:

(defn exemplar [a & {:keys [b c] :or {b 5}}]
  (let [c (or c (* 7 b))]
    (println a b c)))
 31
Author: metasoarous,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-01-27 22:52:12

Istnieje inne podejście, które warto rozważyć: częściowe funkcje. Są to prawdopodobnie bardziej "funkcjonalne" i bardziej elastyczne sposoby określania wartości domyślnych dla funkcji.

Zacznij od utworzenia (jeśli to konieczne) funkcji, która ma parametr (- Y), który (- E) chcesz podać jako domyślny (- e) jako parametr (- y) wiodący (- E):

(defn string->integer [base str]
  (Integer/parseInt str base))

Dzieje się tak, ponieważ Wersja Clojure partial pozwala podać "domyślne" wartości tylko w kolejności, w jakiej są wyświetlane w funkcji definicja. Po uporządkowaniu parametrów można utworzyć "domyślną" wersję funkcji za pomocą funkcji partial:

(partial string->integer 10)

W celu wywołania tej funkcji wiele razy można umieścić ją w var używając def:

(def decimal (partial string->integer 10))
(decimal "10")
;10

Możesz również utworzyć "domyślną lokalną" używając let:

(let [hex (partial string->integer 16)]
  (* (hex "FF") (hex "AA")))
;43350

Podejście funkcji częściowej ma jedną kluczową przewagę nad innymi: konsument funkcji może nadal decydować, co jest domyślne wartość będzie raczej producentem funkcji bez konieczności modyfikowania definicji funkcji . Jest to zilustrowane w przykładzie z hex gdzie zdecydowałem, że domyślna funkcja {[10] } nie jest tym, czego chcę.

Kolejną zaletą tego podejścia jest to, że można przypisać funkcji domyślnej inną nazwę (dziesiętne, hex, itp.), która może być bardziej opisowa i / lub inny zakres (var, local). Funkcja częściowa może być również mieszana z niektórymi z podejście powyżej w razie potrzeby:

(defn string->integer 
  ([s] (string->integer s 10))
  ([base s] (Integer/parseInt s base)))

(def hex (partial string->integer 16))
W odpowiedzi Briana na to pytanie Briana, Briana, Briana, Briana, Briana, Briana, Briana, Briana, Briana, Briana, Briana, Briana, Briana, Briana, Briana, Briana, Briana, Briana, Briana, Briana, Briana, Briana, Briana, Briana, Briana]}
 8
Author: optevo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-07-26 16:04:46

Możesz również przyjrzeć się (fnil) https://clojuredocs.org/clojure.core/fnil

 5
Author: celwell,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-09-21 05:17:46