25

デフォルトで複数のバインディングwhen-letをサポートしないのはなぜですか?if-let

それで:

(when-let [a ...
           b ...]
  (+ a b))

...それ以外の:

(when-let [a ...
  (when-let [b ...
    (+ a b)))

私は自分のマクロを書いたり、モナドを使用したりできることを知っています(ここで説明されているように:http://inclojurewetrust.blogspot.com/2010/12/when-let-maybe.html)。

4

3 に答える 3

15

なぜなら(if-let少なくとも)「他の」ケースをどうするかは明らかではないからです。

少なくとも、if-letをclojureにネストするためのより良い方法に動機付けられて、これを行うマクロを書き始めました。与えられた

(if-let* [a ...
          b ...]
  action
  other)

それは生成します

(if-let [a ...]
  (if-let [b ...]
    action
    ?))

続行する方法がわかりませんでした(「else」には2つの場所があります)。

失敗には単一の選択肢があるべきである、または失敗にはないはずだと言うことができますがwhen-let、テストのいずれかが状態を変化させる場合、物事は依然として厄介になります。

要するに、私が予想していたよりも少し複雑なので、現在のアプローチでは、ソリューションがどうあるべきかについて電話をかける必要がないのではないかと思います。

同じことを言う別の方法:あなたはのif-letように入れ子にするべきだと仮定していますlet。より良いモデルはcond、「ネストされたif」ではなく、より「代替のif」であるため、スコープにうまく適合しない可能性があります...または、別の言い方をすれば、ifこのケースを処理しませんより良い。

于 2012-07-26T19:00:50.533 に答える
8

これがいつです-let*:

(defmacro when-let*
  "Multiple binding version of when-let"
  [bindings & body]
  (if (seq bindings)
    `(when-let [~(first bindings) ~(second bindings)]
       (when-let* ~(vec (drop 2 bindings)) ~@body))
    `(do ~@body)))

使用法:

user=> (when-let* [a 1 b 2 c 3]
                (println "yeah!")
                a)
;;=>yeah!
;;=>1


user=> (when-let* [a 1 b nil c 3]
                (println "damn! b is nil")
                a)
;;=>nil


これがif-let*です:

(defmacro if-let*
  "Multiple binding version of if-let"
  ([bindings then]
   `(if-let* ~bindings ~then nil))
  ([bindings then else]
   (if (seq bindings)
     `(if-let [~(first bindings) ~(second bindings)]
        (if-let* ~(vec (drop 2 bindings)) ~then ~else)
        ~else)
     then)))

使用法:

user=> (if-let* [a 1 
                 b 2 
                 c (+ a b)]
              c
              :some-val)
;;=> 3

user=> (if-let* [a 1 b "Damn!" c nil]
              a
              :some-val)
;;=> :some-val

編集:バインディングはelse形式でリークされるべきではないことが判明しました。

于 2016-03-22T17:13:41.210 に答える
5

を使用するcatsと、mlet便利な関数があります。

(use 'cats.builtin)
(require '[cats.core :as m])
(require '[cats.monad.maybe :as maybe])

(m/mlet [x (maybe/just 42)
         y nil]
  (m/return (+ x y)))
;; => nil

ご覧のとおり、nil値に遭遇すると、mletは短絡します。

(セクション6.5.1 nilから)

于 2015-09-14T11:46:34.897 に答える