如何在Clojure中进行列表推导?

8
我正在学习Clojure,我在一本Haskell书中找到了使用列表推导式解决直角三角形问题的方法,使问题得到了简洁的解决:
寻找直角三角形
  • 三边的长度都是整数。
  • 每条边的长度小于或等于10。
  • 三角形周长(三边长度之和)等于24。
在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)]

在Clojure中是否存在如此优雅的列表推导解决方案?
2个回答

13

Clojure有for语法:

(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])

10
(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])

你还可以通过在c和a绑定之间插入:let [c2 (* c c)],然后在:when中使用c2来避免不必要的平方c从而大幅提高性能。

Clojure的for基本上是列表单子的do-notation,其中:when行为类似于guard:let则类似于let。还有:while,但我不知道它对应什么Haskell东西。


:while 在列表单子里并没有特定对应的东西。不过在其他单子里会有对应。也许是分裂幺半群 - J. Abrahamson
这个问题或者被接受的答案中有一个 off-by-one 错误 (c vc (inc c))。 - Matt Luongo
并不完全是这样。被接受的答案做了“显而易见”的事情,即搜索所有a/b/c三元组,这很好。这个答案观察到,对于a^2 + b^2 = c^2的正解,c必须大于a或b中的任何一个,并且对于整数解,b!= a,因此没有必要搜索具有重复值的三元组。我认为这也很好;两个答案都不需要修复。 - amalloy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接