2010-07-08 3 views

ответ

144

Функция может иметь несколько подписей, если подписи различаются по arity. Вы можете использовать это для предоставления значений по умолчанию.

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

Обратите внимание, что при условии false и nil оба считаются не значения, (if (nil? base) 10 base) может быть сокращен до (if base base 10), или, кроме того, чтобы (or base 10).

+3

Я думаю, что было бы лучше для второй линии, чтобы сказать '(RECUR s 10)', используя [ 'recur'] (HTTP: //grimoire.arrdem .com/1.6.0/clojure.core/recur /) вместо повторения имени функции 'string-> integer'. Это облегчит переименование функции в будущем. Кто-нибудь знает какую-либо причину не использовать 'recur' в этих ситуациях? –

+9

Похоже, что 'recur' работает только с той же аркой. если вы попытались повторить выше, например: 'java.lang.IllegalArgumentException: Неисправный аргумент count для возврата, ожидаемый: 1 args, got: 2, компиляция:' – djhaskin987

+0

Иди в эту же проблему. Было бы разумно иметь сам вызов функции (т. Е. '(String-> integer s 10)')? –

140

Вы также можете разрушить аргументы rest как карты, так как Clojure 1.2 [ref]. Это позволяет назвать и предоставлять по умолчанию для функции аргументов:

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

Теперь вы можете позвонить

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

или

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

Вы можете увидеть это в действии здесь: https://github.com/Raynes/clavatar/blob/master/src/clavatar/core.clj (к примеру)

+1

Так легко понять, если исходить из фона Python :) – Dan

+1

Это гораздо легче понять, чем принятый ответ ... это принятый [«Кложурийский»] (https://github.com/bbatsov/clojure-style -guide)? Пожалуйста, подумайте над добавлением в этот документ. – Droogans

+1

У меня есть [добавлена ​​проблема] (https://github.com/bbatsov/clojure-style-guide/issues/37) в неофициальное руководство по стилю, чтобы помочь решить эту проблему. – Droogans

31

Данное решение является ближе к дух исходного раствора, но незначительно уборщика

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

Аналогичная картина, который может быть удобно использование or в сочетании с let

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

В то время как в этом случае более развернутого, он может быть полезен если вы хотите иметь значения по умолчанию в зависимости от других входных значений. Например, рассмотрим следующую функцию:

(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 

Этот подход может быть легко расширен для работы с именованными аргументами (как в растворе М. Gilliar в), а также:

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

Или используя еще от слияния:

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

Если вам не нужны ваши значения по умолчанию, зависящие от других значений по умолчанию (или, возможно, даже если вы это сделаете), решение по Matthew выше также допускает несколько значений по умолчанию для разных переменных. Это намного чище, чем использование регулярных 'или' – johnbakers

+0

Согласовано; Я обновлю, чтобы это отразить. Благодарю. – metasoarous

+0

Я Clojure noob, поэтому, возможно, OpenLearner прав, но это интересная альтернатива решению Мэтью выше. Я рад узнать об этом, решаю ли я его использовать или нет. – GlenPeterson

8

Существует другой подход вы, возможно, захотите рассмотреть следующие вопросы: partial функции. Это, возможно, более «функциональный» и более гибкий способ указания значений по умолчанию для функций.

Начните с создания (при необходимости) функцию, которая имеет параметр (ы), которые вы хотите предоставить по умолчанию (ы) в качестве ведущего параметра (ов):

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

Это сделано потому, что Clojure-х версия partial позволяет вам указывать значения по умолчанию только в том порядке, в котором они отображаются в определении функции.После того как параметры были заказаны по желанию, вы можете создать версию функции «по умолчанию» с помощью partial функции:

(partial string->integer 10) 

Для того, чтобы сделать эту функцию вызываемые несколько раз, вы можете поместить его в вар, используя def:

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

Вы также можете создать "локальный" по умолчанию с помощью let:

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

Частичный функциональный подход имеет одно ключевое преимущество перед другими: потребитель функции все еще может решить, чем будет использоваться значение по умолчанию, а не функции без необходимости изменять определение функции. Это проиллюстрировано в примере с помощью hex, где я решил, что функция по умолчанию decimal не то, что я хочу.

Другим преимуществом такого подхода является назначение функции по умолчанию другим именем (десятичным, шестнадцатеричным и т. Д.), Которое может быть более наглядным и/или другим областью (var, local). Частичная функция также может быть смешан с некоторыми из подходов выше, при желании:

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

(def hex (partial string->integer 16)) 

(Обратите внимание, это немного отличается от ответа Брайана, как порядок параметров был отменен по причинам, указанным в верхней части этого ответ)

+1

Это не то, о чем спрашивает вопрос; это интересно. – Zaz

Смежные вопросы