逆FizzBuzz
http://www.jasq.org/2/post/2012/05/inverse-fizzbuzz.html
http://d.hatena.ne.jp/matarillo/20120515/p1
より。
入力を正規表現に変換してしまえばとても簡単になる。
https://gist.github.com/2708823
けれど、cl-ppcreだと上記のコードのままじゃちょっと長めの入力を渡すと死んでしまう。
バックトラックが爆発してるんだろうけど、正しい書き方あるのかな。
CL-USER(10): (defun test (n) (time (inverse-fizzbuzz (loop repeat n append '(fizz buzz fizz fizz buzz fizz fizzbuzz))))) TEST CL-USER(11): (test 5) Evaluation took: 0.091 seconds of real time 0.093601 seconds of total run time (0.093601 user, 0.000000 system) 103.30% CPU 225,231,803 processor cycles 65,520 bytes consed (3 75) CL-USER(12): (test 6) Evaluation took: 8.923 seconds of real time 8.907657 seconds of total run time (8.907657 user, 0.000000 system) 99.83% CPU 22,234,078,381 processor cycles 98,296 bytes consed (3 90) CL-USER(13): (test 7) ;; 返って来ない…
7個以上渡された時は最初の7個の繰り返しになってるか確認してから最初の7個をチェック、で終点は入力の長さから計算って形にしないといけなさそう。
user> (defun scan-all (re str &optional (start 0)) (let ((s (string-match re str start))) (when s (cons (list (1+ s) (match-end 0)) (scan-all re str (1+ s)))))) scan-all user> (defun inverse-fizzbuzz (fb) (let ((re (format nil "~{~A~^_*?~}" (mapcar #'(lambda (s) (case s (fizz "f") (buzz "b") (t "z"))) fb))) (pattern (format nil "~V@{__f_bf__fb_f__z~}" (+ 2 (floor (length fb) 7)) t))) (car (sort (scan-all re pattern) #'> :key (lambda (p) (apply #'- p)))))) inverse-fizzbuzz user> (defun test (n) (inverse-fizzbuzz (loop repeat n append '(fizz buzz fizz fizz buzz fizz fizzbuzz)))) test user> :time (test 5) (3 75) ---------- 0.000 sec. user> :time (test 10) (3 150) ---------- 0.000 sec. user> :time (test 1000) (3 15000) ---------- 0.484 sec.
7000個渡しても大丈夫。
lisp-repl-mode for xyzzy
Lisp処理系には付き物のREPLですが、xyzzy lisp用の物はありそうで見つからなかったので作りました。
標準の*scratch*では面倒だった*package*の切り替えが簡単になったり、色々捗ります。
標準の*scratch*に比べて良い点
- カレントパッケージを切り替えられる
- *buffer-package*の更新も行うので、ac-modeやldocを導入している場合色々便利に
- REPL変数が使える
- 便利なREPLコマンド (自作可)
注意点
rx.lを導入している場合、rx.l内で使用されているシンボル'ed::**と
xl-repl.l中でlispパッケージよりexportしようとしている'lisp:**がコンフリクトします。
rx.lより先(ni/setupより先)にxl-replをロードするか、siteinit.lの先頭に
(export '(lisp::** lisp::*** lisp::++ lisp::+++ lisp::// lisp::///) :lisp)
というコードを書くなどして回避してください。
インストール
NetInstallerにhttp://youz.github.com/xyzzy/package.lを登録して*scratch*よりインストールし、.xyzzy (or siteinit.l) に
(require "xl-repl")
と追記してください。
設定
ac-modeやldoc2を導入している場合、以下の設定を.xyzzyに加えておくと便利です。
; ldoc2 を使っている場合 (push 'ed:lisp-repl-mode ed::*ldoc-activated-mode-list*) ; ac-mode を使っている場合 (push 'ed:lisp-repl-mode ed::*ac-mode-lisp-mode*)
REPLバッファ上で、パッケージ修飾子無しでもカレントパッケージからシンボル名補完ができたり、ldoc2での説明表示ができるようになります。
起動
M-x start-repl
キーマップ
REPLバッファ用キーマップ repl:*keymap* は、 ed:*lisp-mode-map* をベースにして以下のキーバインドを追加/上書きしています。
- RET -- repl::newline-or-eval-input (入力した式を評価 / 書きかけならlisp-newline-and-indent)
- C-l -- repl::clear-repl (REPLバッファをクリア)
- M-C-a -- repl::beginning-of-input (入力中の式の先頭へ移動)
- M-C-e -- repl::end-of-input (入力中の式の最後へ移動)
- C-p -- repl::previous-input (入力履歴 - 戻る)
- C-n -- repl::next-input (入力履歴 - 進む)
REPLコマンド
以下のキーワードシンボル(と引数)を入力するとREPLコマンドを実行します。
:cd (&optional dir) ; default-directoryをdirへ移動 (dir省略時はdefault-directoryを表示) :describe (symbol-or-package-name) ; パッケージ/変数/定数/関数の説明を表示 :dir (&optional wildcard) ; default-directoryのファイルを列挙 :expand (form) ; formをmacroexpandして表示 :help (&optional pattern) ; REPLコマンドの説明を表示 :load (name) ; *load-path*にdefault-directoryを含めて(load-library 'name)を評価 :ls (&optional pat (pkg *package*)) ; パッケージ内の変数/定数/関数シンボルを列挙 :lsall (&optional pattern) ; 全パッケージの変数/定数/関数シンボルを列挙 :lsext (&optional pattern (pkg *package*)) ; パッケージよりexportされている変数/定数/関数シンボルを列挙 :lspkg (&optional pattern) ; パッケージ名を列挙 :mkpkg (name &rest options) ; (make-package 'name [options])を評価し、*package*を作成したパッケージに変更 :package (name) ; (in-package 'name)を評価 :require (name) ; *load-path*にdefault-directoryを含めて(require 'name)を評価 :time (form) ; formを評価し、実行時間(秒)を表示
適当に省略してもOK。
user> :pa repl.command ; :packageコマンド #<package: repl.command> repl.command> :de package ; :describeコマンド <Function> repl.command::package (name) ; (in-package 'name)を評価
:cd コマンドは今の所引数に文字列しか受け付けないので注意
user> :cd site-lisp 不正なデータ型です: site-lisp: pathname user> :cd "site-lisp" c:/usr/xyzzy/site-lisp user> :cd "C:/Users/yz" C:/Users/yz
他のコマンドはシンボルを渡してもOK。
user> :dir *x*
[C:/Users/yz/]
.VirtualBox/
Dropbox/
lynx.rc
lynx_bookmarks.htm
VirtualBox VMs/
REPLコマンドの自作
パッケージrepl.command内に関数を定義すると、その関数がREPLコマンドとして使えるようになります。
定義例はソースを見てください。
repl.commandパッケージはlispパッケージをuseしていないので、(in-package :repl.command)と書いてから追加コマンドを定義するのは色々面倒です。
lispやeditorをuseしている適当なパッケージから(defun repl.command::hoge () ...)と書く方が良いでしょう。
(repl.commandパッケージがlispパッケージをuseしていないのは、loadやrequireといったlispパッケージにあるような名前のコマンドを簡単に作成したかった為です)
不具合等
見つかりましたら githubのissuesか@Yubeshiまで。
投稿モードバッファ (xyttr Advent Calendar 25日目分)
3日遅れでxyttr Advent Calendar 2011の最終記事です。
xyttrはあまりツイートしない人間が作ってる事もあって投稿機能に力が入ってないのですが、もうちょっと何かあった方が良いよなーという事で今後のために投稿用バッファのプロトタイプを作ってみました。
hatena-haiku-modeの投稿画面を参考にしています。
https://gist.github.com/1522725
このファイルをロードすると投稿系のキーバインド(u, @, S-@, r u, r r)が下図のような投稿用バッファを開くコマンドに変更されます。
C-c C-cで罫線以下のテキストが投稿されます。
今の所特殊な編集機能はありませんが、ミニバッファでの操作制限(undo等)がなくなっただけでも結構便利になったかと思います。というか今までが不自由すぎたか…
年末・年始で色々試して、次のリリースまでに本体へ組み込みたいと思います。
xyttrで画像投稿 (xyttr Advent Calendar 24日目分)
完全に遅刻ですがxyttr Advent Calendar 2011の記事です。
xyttrでやる意味あるの? というと利便性上ほとんど意味ないですが、出来てしまった物はしかたがない。
https://gist.github.com/1521515
xyttr::tweet-with-photoを適当なキーに割り当てるか、M-x xyttr::tweet-with-photoで実行します。
実装ですが、connect関数使ってベタで書いてるのはxhrだとこの辺の問題で投稿が失敗(500)してしまうため。
Msxml2.XMLHTTP.6.0を使うようxhrを書き換えて試してみましたが、タイムライン系api等のapi.twitter.comへのリクエストは問題なかったものの画像アップロードは403でした。
ちゃんとパケット調べてないけどやはり余計な0x00で問題起きてそう。
read it laterをxyttrで見る (xyttr Advent Calendar 23日目分)
この記事はxyttr Advent Calendar 2011の記事です。
14日目のタイムラインコマンド自作の応用で、read it laterに貯め込んだURLをxyttrで表示してみます。
read it later viewer for xyttr
URLの上でmキーを押すと既読マークを付けます、が手抜きなのでステータスバーにメッセージが出るだけで見た目変わりません。起動しなおすとエントリーが消えてます。
もう1つ、read it laterにURLを登録するコマンド ril-focused-url を用意してあります。このコードではr-i-lというキーシーケンスに割り当ててますが適当に変更してお使い下さい。
timeline-draw-statuses (xyttr Advent Calendar 22日目分)
この記事はxyttr Advent Calendar 2011の記事です。
関数xyttr::timeline-draw-statusesを使った小ネタを2つ。
- *function* timeline-draw-statuses (buf statuses &key (point 0)) ツイートデータを整形してバッファに出力します。 * buf -- 出力先バッファ * statuses -- ツイートデータのリスト * point -- 出力先位置
◆ 栞を挟む
(in-package :xyttr) ;; ツイートデータ生成 (defun make-tweet (status-id name text) `(("id" . ,status-id) ("user" ("screen_name" . ,name)) ("text" . ,text) ("created_at" . ,(format-date-string "%a %b %d %H:%M:%S %Z %Y")))) ;; カーソル下のツイートの1つ前に栞を挟む (defun kokomadeyonda2 () (interactive) (when (eq buffer-mode 'xyttr-timeline-mode) (let ((p (1- (entry-point))) (tw (make-tweet nil "xyttr_shiori" (format nil "~V@{◇◆~}" (ash (window-columns) -2) t)))) (w/buffer-modifying () (timeline-draw-statuses (selected-buffer) (list tw) :point p))))) (define-key *xyttr-timeline-keymap* '(#\C-k #\C-m) 'kokomadeyonda2)
◆ トレンドを表示
(define-api trends (woeid exclude) :path (format nil "/1/trends/~A.json" woeid)) (defun show-trend () (interactive) (when (eq buffer-mode 'xyttr-timeline-mode) (let ((buf (selected-buffer))) (api-trends-async :woeid +woeid-tokyo+ :onsuccess (lambda (res) (w/json (trends) (car res) (let* ((text (format nil "trends:~{ ~A~}" (mapcar #'(lambda (tr) (json-value tr name)) trends))) (tw (make-tweet nil "xyttr_trend_info" text))) (save-excursion (set-buffer buf) (w/buffer-modifying () ;; バッファ先頭へ出力 (timeline-draw-statuses buf (list tw)) (refresh-screen)))))))))) (define-key *xyttr-timeline-keymap* #\t 'show-trend)
トレンドの使い途イマイチ分からん