Nick
Nick

Reputation: 9031

How to do list comprehension in Clojure?

I am learning Clojure, and I found the solution to find the right triangle problem in a Haskell book using list comprehension making the problem neatly solved:

Finding the Right Triangle

In Haskell:

ghci> let rightTriangles' = [ (a,b,c) | c <- [1..10], a <- [1..c], b <- [1..a],
a^2 + b^2 == c^2, a+b+c == 24]

ghci> rightTriangles'
[(6,8,10)]

Is there such an elegant list comprehension solution in Clojure?

Upvotes: 8

Views: 3044

Answers (2)

amalloy
amalloy

Reputation: 91837

(for [c (range 1 11)
      a (range 1 c)
      b (range 1 a)
      :when (and (= (+ a b c) 24)
                 (= (* c c) (+ (* a a) (* b b))))]
  [a b c])

You can also improve performance a fair bit by inserting :let [c2 (* c c)] in between the c and a bindings, and then use c2 in the :when, to avoid squaring c more often than necessary.

Clojure's for is basically do-notation for the list monad, with :when acting like guard, and :let acting like let. There's :while too, but I don't know what haskell thing that corresponds to.

Upvotes: 10

J. Abrahamson
J. Abrahamson

Reputation: 74334

Clojure has for syntax:

(for [ c (range 1 (inc 10))
       a (range 1 (inc c))
       b (range 1 (inc a))
       :when (== (+ (* a a) (* b b)) 
                 (* c c))
       :when (== (+ a b c) 24) ]
  [a b c])

Upvotes: 13

Related Questions