2020年3月10日火曜日

数独プログラム

 「 あらゆる数独パズルを解く」はPeter Norvigなのに、Pythonで書かれている。
 じゃあというわけでelispで書いてみた。

(2) ある値に対し、ユニットの中で置ける場所が1つしかないなら、その値をそこに置く。

 は、うまく動かなかったのでコメントアウトしているけど。
 それでも「 あらゆる数独パズルを解く」のページの問題はいちおう解けたからだいじょうぶだと思うけど。
 まぁ、よいか。

( defun  test ()
  ( progn (sudoku-init)
(sudoku-set  "
 . . 5 |3 . . |. . . 
 8 . . |. . . |. 2 . 
 . 7 . |. 1 . |5 . . 
 ------+------+------
 4 . . |. . 5 |3 . . 
 . 1 . |. 7 . |. . 6 
 . . 3 |2 . . |. 8 . 
 ------+------+------
 . 6 . |5 . . |. . 9 
 . . 4 |. . . |. 3 . 
 . . . |. . 9 |7 . . 
 ")
       (sudoku-solve)
       (sudoku-print)))

(benchmark 1 '(test))
| 1 4 5 | 3 2 7 | 6 9 8 |
| 8 3 9 | 6 5 4 | 1 2 7 |
| 6 7 2 | 9 1 8 | 5 4 3 |
|-------+-------+-------|
| 4 9 6 | 1 8 5 | 3 7 2 |
| 2 1 8 | 4 7 3 | 9 5 6 |
| 7 5 3 | 2 9 6 | 4 8 1 |
|-------+-------+-------|
| 3 6 7 | 5 4 2 | 8 1 9 |
| 9 8 4 | 7 6 1 | 2 3 5 |
| 5 2 1 | 8 3 9 | 7 6 4 |
 "Elapsed time: 0.179490s (0.093774s in 1 GCs)"

 ベンチマークもそこそこ。

2020年3月6日金曜日

dash.el(2)

 たとえば、(1 2 3)と(4 5 6)を組み合わせたい。

((1 . 4) (2 . 4) (3 . 4) (1 . 5) (2 . 5) (3 . 5) (1 . 6) (2 . 6) (3 . 6))

 みたいな感じに。
 そこで

( defun  y-combination-of-list (list1 list2)
   "list1の要素とlist2の要素を組み合わせた結果をconsして出力する。"
  ( loop for x in list1
        collect ( loop for y in list2
                      collect (cons x y))))

 というのをでっちあげた。でもこれだと結果は

(((1 . 4) (1 . 5) (1 . 6)) ((2 . 4) (2 . 5) (2 . 6)) ((3 . 4) (3 . 5) (3 . 6)))

 という風になってしまう。
 これを入れ子のリストではなく、フラットなリストにしたい。
 それで「 dash.el」の「-flatten」が必要だったのだけど。

(-flatten '(((1 . 4) (1 . 5) (1 . 6)) ((2 . 4) (2 . 5) (2 . 6)) ((3 . 4) (3 . 5) (3 . 6))))
((1 . 4) (1 . 5) (1 . 6) (2 . 4) (2 . 5) (2 . 6) (3 . 4) (3 . 5) (3 . 6))

 よくよく考えたら「dash.el」に、そもそもそんな関数があるんじゃないか? つらつら「 https://github.com/magnars/dash.el#functions」を見ていたら。

(-table-flat 'cons '(1 2 3) '(4 5 6))
((1 . 4) (2 . 4) (3 . 4) (1 . 5) (2 . 5) (3 . 5) (1 . 6) (2 . 6) (3 . 6))

 あった。

2020年3月5日木曜日

dash.el

 どのパッケージがきっかけでインストールされたのか、わからないけれど、「dash.el」がインストールされている。

;;; dash.el --- A modern list library for Emacs

 だそうだ。
 「-flatten」というのがあってお気に入り。

(-flatten '((1 2 3)(4 5 6)))
(1 2 3 4 5 6)

 で、素の ABCLを使っていて「flatten」が必要になった。
 「alexandria」をインストールすれば、いいんだろうが、諸事情というものがある。
 「dash.el」の「-flatten」が使えないもんだろうか。
 「–map」「–mapcat」「-mapcat」「-flatten」を喰わせてみたところ。

(-flatten '((1 2 3)(4 5 6)))
(1 2 3 4 5 6)

 動いた。

2020年3月3日火曜日

async.el

 helmをインストールすると、もれなくasync.elがついてくる。
 Emacsの非同期ライブラリである。
 バックグラウンドでEmacsをもうひとつ、立ち上げてそちらで処理させる、というもの。

( setq wrk (async-start
           ( lambda ()
             222)))
-- 割愛 --

(async-get wrk)
222

 システムモニタを立ち上げておくと、Emacsがもうひとつ、起動されるのがわかる。
 100個とか、無理だろうけど 1

( setq wrk ( loop for x from 1 to 10
                collect (async-start
                         `( lambda ()
                            ,x))))
-- 割愛 --

( loop for x in wrk
      collect (async-get x))
(1 2 3 4 5 6 7 8 9 10)

 カンマを使えば、変数の中身を展開できるけど、さすがにクロージャーでデータを渡すのは無理だろうなぁ。別プロセスだもんなぁ。スレッドならできるのだろうけど。
 ——と思ったけれど、やってみたらできた。
 驚いた。

( setq lexical-binding t)
t

( defun  wrk (x)
  ( lambda()
    x))
wrk

( setq wrk ( loop for x from 1 to 10
                collect (async-start (wrk x))))
-- 割愛 --

( loop for x in wrk
      collect (async-get x))
(1 2 3 4 5 6 7 8 9 10)

 なんで?

(wrk 1)
(closure ((x . 1) t) nil x)

 ああ、クロージャーはリストに展開されるんだ。
 なるほど。それならpipe渡しでも可能だ。あれ? ということはelispだからできるってこと?
 ほえぇ。elispはあなどれない。

Footnotes:

1

Emacs for Windowsでは10個でエラーになった。