If-else, ветвящийся в clojure
Я учу себя Clojure.
В языке, отличном от FP, я мог бы легко написать вложенные if, и если бы я не специально помещал else, тогда управление просто выходило бы из блока if. Например:
Thing myfunc()
{
if(cond1)
{
if(cond2)
return something;
}
return somethingelse;
}
Однако в Clojure нет оператора return (который я знаю), поэтому, если я пишу:
(defn myfunc []
(if (cond1)
(if (cond2) something))
somethingelse)
тогда нет "возврата" на "что-то". Кажется, это просто сказать, хорошо, здесь у нас есть ценность, теперь пусть продолжит выполнение. Очевидным решением было бы объединение условий, т.е.:
(if (and (cond1) (cond2))
something
somethingelse)
но это становится громоздким/уродливым при больших условиях. Кроме того, для добавления заявления в "else" часть cond1 потребуется дополнительное обновление. Есть ли какое-то элегантное решение для этого?
Ответы
Ответ 1
Это тонкая разница между императивным и функциональным подходом. С императивностью вы можете разместить return
в любом месте функции, а с функционалом лучше всего иметь ясные и явные пути искушения. Некоторые люди (включая меня) предпочитают последний подход и в императивном программировании, признавая его более очевидным и управляемым и менее подверженным ошибкам.
Чтобы сделать эту функцию явной:
Thing myfunc() {
if(cond1) {
if(cond2)
return something;
}
return somethingelse;
}
Вы можете реорганизовать его на:
Thing myfunc() {
if(cond1 && cond2) {
return something;
} else {
return somethingelse;
}
}
В Clojure его эквивалент:
(defn myfunc []
(if (and cond1 cond2)
something
somethingelse))
Если вам нужно "else", ваша версия Java может стать:
Thing myfunc() {
if(cond1) {
if(cond2) {
return something;
} else {
return newelse;
}
} else {
return somethingelse;
}
}
... и его эквивалент Clojure:
(defn myfunc []
(if cond1
(if cond2 something newelse)
somethingelse))
Ответ 2
(if (and (cond1) (cond2))
something
somethingelse)
(cond
(and (cond1) (cond2)) something
:else somethingelse)
cond
делает это, если вы хотите сравнить одно и то же; в коммутационном шкафу вы можете использовать condp
.
Я не очень часто вижу такой код, но это способ сделать это.
Ответ 3
Императивные языки имеют if-утверждения, которые говорят, что if this then do that else do that
и функциональные языки имеют if-выражения, которые говорят if this return that else return this
. это другой способ взглянуть на ту же идею, что отражает совсем другой подход к выражению проблем. в функциональных языках все имеет значение, действительно все, даже если вы ничего не делаете с этим значением.
Когда я делал переход, мне очень помогало спросить себя: "какой результат должна вернуть эта функция", а не вопрос "что должна делать эта функция", которую я привык задавать.
Ответ 4
В Clojure нет явного оператора return, но ваш код будет "возвращаться" на "что-то", потому что после этого if
и последнее выражение используется как возвращаемое значение функции.
Ответ 5
Вы также можете использовать макрос (cond)
:
(defn length-checker [a b]
(cond
(= 3 (count (str a))) (if (= 3 (count (str b)))
(println "both numbers are 3 digits long")
(println "first number is 3 digits, but the 2nd not!"))
:else (println "first- or both of the numbers are not 3 digits")))