kikkiiのブログ

ひきこもり

Common Lispでリスト内包表記

リストを生成するとき、リスト内包表記(List comprehensions)で書けると可読性がよくなる。ロゼッタコードの当該部分を参考にしながらHaskellPythonClojure、そしてCommon Lispで内包表記を使ってみる。

Haskellでリスト内包表記:

[(a,b,c) |
 a <- [1..19],
 b <- [a..19],
 c <- [b..19],
 a^2 + b^2 == c^2]

-- 結果
[(3,4,5),(5,12,13),(6,8,10),(8,15,17),(9,12,15)]

Pythonでリスト内包表記:

[(a,b,c) 
 for a in range(1,20) 
 for b in range(a,20) 
 for c in range(b,20) 
 if a**2 + b**2 == c**2]

# 結果
[(3, 4, 5), (5, 12, 13), (6, 8, 10), (8, 15, 17), (9, 12, 15)]

Clojureでリスト内包表記:

(for [a (range 1 20)
        b (range a 20)
        c (range b 20)
        :when (= (+ (* a a) (* b b)) (* c c))]
    [a b c])

;; 結果
([3 4 5] [5 12 13] [6 8 10] [8 15 17] [9 12 15])

Common Lispで...:

(loop for a from 1 to 19
        append (loop for b from a to 19
                     append (loop for c from b to 19
                                  when (= (+ (* a a) (* b b)) (* c c))
                                  collect (list a b c))))

;; 結果
((3 4 5) (5 12 13) (6 8 10) (8 15 17) (9 12 15))

最後のは読みにくい。素のCommon Lispではリスト内包表記が使えないみたいなので、残念だ。でもincf-clを使えば大丈夫、Common Lispでも内包表記っぽいものが使えて、万事解決。


Common Lispでリスト内包表記:

;; 準備
(ql:quickload :incf-cl)
(use-package :incf-cl)

(lc (list a b c) 
    (<- a (range 1 19)) 
    (<- b (range a 19)) 
    (<- c (range b 19))
    (= (+ (* a a) (* b b)) (* c c)))

;; 結果
((3 4 5) (5 12 13) (6 8 10) (8 15 17) (9 12 15))