labunix's blog

labunixのラボUnix

難しく考えれば難しくなるというお話。clispとbashの例。

■例えば以下を題材に、bashとclisp(とawk)を組み合わせると、
 読みやすくシンプルに出来る。

 2013/01/14 bashとclispとawkで小学三年生レベルの等差数列の総和
 http://d.hatena.ne.jp/labunix/20130114

$ echo "(+ "`seq 1 100`")" | clisp -q
[1]> 
5050

■これは途中、以下のようなリストが出来る。

$ echo "(+ "`seq 1 100`")" | sed s/".\{63\}"/"&\n"/g
(+ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 
45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 
87 88 89 90 91 92 93 94 95 96 97 98 99 100)

■動きとしては以下と同じ。

$ echo "`seq 1 100`" | awk '{sum+=$1};END{print sum}'
5050

■最大値をsum関数に渡して1までの和を得る方法。

$ echo '
(defun sum (n) 
  (if (= n 0) 0 
    (+ n (sum (- n 1))))) 
(sum 100)
' | clisp -q
[1]> 
SUM
[2]> 
5050

■動きとしては、100から1のリストになった程度。

$ echo "`seq 100 -1 1`" | awk '{sum+=$1};END{print sum}'
5050

■最大値100までのリストXを作って、sum関数でxのリストから値を取り出して計算する。
 別出しにも出来るけど、loop内に収めた。。。

$ echo '
(setq i 100) 
(setq x nil)
(loop (if (= i 0) (return i)) 
  (setq x (cons i x)) 
  (setq i (- i 1))) 
  (defun sum (x) (if (null x) 0 (+ (car x) (sum (cdr x))))
) 
(sum x)
' | clisp -q
[1]> 
100
[2]> 
NIL
[3]> 
0
[4]> 
SUM
[5]> 
5050

■これは少々面倒で、まず最大値の100までのリストを作る。
 ここには演算子の「+」が含まれないので、
 sum関数でいちいちリストから取り出しながら計算しないといけない。

$ echo "(quote ("`seq 1 100`"))" | clisp -q
[1]> 
(1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100)

$ echo '
(setq i 100) 
(setq x nil)
(loop (if (= i 0) (return i)) 
  (setq x (cons i x)) 
  (setq i (- i 1))
)
x' | clisp -q
[1]> 
100
[2]> 
NIL
[3]> 
0
[4]> 
(1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100)

■bashでは、一度配列に入れて、その値を再度呼び出すようなもの。

$ list=(`seq 100 -1 1`);\
  for n in `seq 0 99`;do echo ${list[$n]};done | \
  awk '{sum+=$1};END{print sum}'
5050