まず、C++の手続きをそのままClojureで翻訳しようと試みました。
;; Problem 1
;; 問題 1 (悪い例)
(defn solve [m cards]
(doseq [a cards]
(doseq [b cards]
(doseq [c cards]
(doseq [d cards]
(if (= (+ a b c d))
"Yes"
"No"))))))
;; テスト
(solve 9 '(1 3 5))
(solve 10 '(1 3 5))
C++コードと同様、単純な4重ループですね。
しかし、これはうまくいきません。なぜなら、doseq の戻り値は nil であり、doseq 自体が手続き型言語のように副作用のある処理を行うものだからです。
そこで、発想を変え、「結果を出すために、どういうリストが必要なのか」という視点で考えてみると、以下のようになりました。
;; 問題 1
(defn solve [m cards]
(let [p (for [a cards b cards c cards d cards] (list a b c d))]
(let [m-list (filter (fn [l] (= (apply + l) m)) p)]
(if (= (count m-list) 0))
"Yes"
"No")))
;; テスト
(solve 9 '(1 3 5)); => "No"
(solve 10 '(1 3 5)); => "Yes"
「プログラミングコンテストチャレンジブック」には、この問題にはさらに効率的な解法が存在するということで、これも後日Clojureで解いてみたいと思います。