#:g1: frontpage

 

cl-epochの紹介

Posted 2014-10-30 15:00:00 GMT

(LISP Library 365参加エントリ)

 LISP Library 365 の304日目です。

cl-epochとはなにか

 cl-epochは、Andrew Pennebaker氏作のCommon LispのUniversal TimeとPosix time(Epoch time)との変換のライブラリです。

パッケージ情報

パッケージ名cl-epoch
Quicklisp
参考サイトThe Common Lisp and Unix epochs
Quickdocscl-epoch | Quickdocs
CL Test Grid: ビルド状況cl-epoch | CL Test Grid

インストール方法

(ql:quickload :cl-epoch)

試してみる

 どんな関数があるかは、Quickdocsで確認できます。

 ソースコードにも書いてありますが、Common Lisp TipsのThe Common Lisp and Unix epochsの回のコードそのまんまです。
使い方は、シンプルで3つ関数があるのみです。

(cl-epoch:get-epoch-time)
;=>  1414252610

(cl-epoch:universal->unix-time (encode-universal-time 0 0 0 1 1 1970 0)) ;=> 0

(cl-epoch:unix->universal-time (cl-epoch:get-epoch-time)) ;=> 3623241412

まとめ

 今回は、cl-epochを紹介してみました。
一発物で、しかもブログのコードを第三者がQuicklispにまとめただけという物ですが、example.lispにサンプルコードが用意されている辺り好感が持てます。

clapの紹介

Posted 2014-10-29 15:00:00 GMT

(LISP Library 365参加エントリ)

 LISP Library 365 の303日目です。

clapとはなにか

 clapは、Ryohei Ueda氏によるPythonの標準ライブラリをCommon Lispに実現しようというプロジェクトです。

パッケージ情報

パッケージ名clap
Quicklisp×
プロジェクトサイトgaraemon/clap · GitHub

インストール方法

 上記のプロジェクトサイトからチェックアウトしてきてQuicklispのlocal-projectsに置けば

(ql:quickload :clap)

可能です。

試してみる

 2010年末に始まったプロジェクトですが、3年位前から動きが停滞しています。
現在実装されているところとしては、

  • pwd
  • argparse
  • sys
  • os
  • hashlib
  • string
  • builtin

 あたりで

  • clap-pwd
  • clap-argparse
  • clap-sys
  • clap-os
  • clap-hashlib
  • clap-string
  • clap-builtin

が上記に相当します。

 少し紹介してみると、

(clap-builtin:whitespacep #\Space)
;=>  #\ 

(clap-os:getenv "LANG") ;=> "ja_JP.UTF-8"

(clap-hashlib:hexdigest (clap-hashlib:md5 "foo")) ;=> "acbd18db4cc2f85cedef654fccc4a4d8"

(clap-builtin:dict '(("greets" . "おはよう")) :test #'equal) ;=> #<HASH-TABLE :TEST EQUAL :COUNT 1 {102EE3E613}>

(clap-string:substitute (clap-string:make-template "$greets日本") (clap-builtin:dict '(("greets" . "おはよう")) :test #'equal)) ;=> "おはよう日本"

みたいなところです。

まとめ

 今回は、clapを紹介してみました。
以前丸ごとQuicklispに申請された時には、まだ発展途上ということで登録は却下されましたが、今なら大分ゆるくなってきたので登録されるかもしれません。もしくはサブモジュールごとに登録というのもありかもしれません。

Hierarchical Packagesの紹介

Posted 2014-10-28 15:00:00 GMT

(LISP Library 365参加エントリ)

 LISP Library 365 の302日目です。

Hierarchical Packagesとはなにか

 Hierarchical Packagesは、Allegro CLとCMUCLでサポートされている、パッケージを階層分けする仕組みです。

パッケージ情報

パッケージ名Hierarchical Packages
Quicklisp×
参考サイトAllegro CL: Packages
CMUCL: Hierarchical Packages

インストール方法

 上記のAllegro CLのドキュメントに参照実装がありますので適当に動かします。
SBCLに移植してみたものがありますので良かったらどうぞ。find-packageを上書きするので注意してください。

 Quicklispのlocal-projects以下に配置すれば、

(ql:quickload :relative-package-names)

で読み込めます。

試してみる

階層的なパッケージとありますが、階層を「.」で区切るという命名規約と、パッケージの相対位置を指定できるようにするrelative-package-namesの2つから成り立っています。
CMUCLでは、18dからAllegro CLの実装を取り入れたようです。
Allegro CL、CMUCL共に起動時のデフォルトで有効になっていて、*features*に:relative-package-namesが入っています。
relative-package-namesの例としては、

;; utilities
(defun children-names (pkg)
  (nreverse
   (maplist (lambda (cdr)
              (format nil "~{~A~^.~}" (reverse cdr)))
            (nreverse (*:split "\\." (string pkg))))))

(defmacro defpackage/parents (name &body options) (let ((pkgs (children-names name))) `(list ,@(mapcar (lambda (p) (eval-when (:compile-toplevel :load-toplevel :execute) `(or (find-package ,p) (defpackage ,p ,@options)))) pkgs))))

(cl:in-package :cl-user) 

(defpackage/parents :a.b.c.d (:use :cl))

(defpackage/parents :a.b.cc.dd (:use :cl))

(cl:in-package :a.b.c.d)

(defun foo (n) (list :a.b.c.d n))

(cl:in-package :a.b.c)

(defun foo (n) (list :a.b.c (a.b.c.d::foo n)))

(defun bar (x) (list :a.b.c x))

(cl:in-package :a.b.c.d)

(defun bar (x) (list :a.b.c.d (a.b.c::bar x)))

(cl:in-package :a.b.cc.dd)

(defun bar (x) (list :a.b.cc.dd (a.b.c::bar x)))

;;; *EOF*

のようなものが、

(cl:in-package :cl-user) 

(defpackage/parents :a.b.c.d (:use :cl))

(defpackage/parents :a.b.cc.dd (:use :cl))

(cl:in-package :a.b.c.d)

(defun foo (n) (list :a.b.c.d n))

(cl:in-package :..)

(defun foo (n) (list :a.b.c (.d::foo n)))

(defun bar (x) (list :a.b.c x))

(cl:in-package :.d)

(defun bar (x) (list :a.b.c.d (..::bar x)))

(cl:in-package :...cc.dd)

(defun bar (x) (list :a.b.cc.dd (...c::bar x)))

;;; *EOF*

のように書けます。

 なんとなくですが、親子階層シンボルへの参照は便利そう、しかしin-packageで相対指定するとカオスなことになりそう、という印象です。
まだ、使いこんでいないのでどの辺りが便利なのかが実感できていないですが、第一印象としては、あまり便利そうでもないかなというところです。

まとめ

 今回は、Hierarchical Packagesを紹介してみました。
Common Lispの前身のZetalisp(Lisp machine Lisp)のパッケージは階層パッケージでしたが、Zetalispを参考にしつつもCommon Lispは階層パッケージにはなりませんでした。
そのうちZetalispの階層パッケージとも比較してみたいところです。

com.informatimago.common-lisp.pictureの紹介

Posted 2014-10-27 15:00:00 GMT

(LISP Library 365参加エントリ)

 LISP Library 365 の301日目です。

com.informatimago.common-lisp.pictureとはなにか

 com.informatimago.common-lisp.pictureは、Pascal Bourguignon氏作の主にコンスセルのアスキーアートの描画機能を持つアスキーアートのライブラリです。

パッケージ情報

パッケージ名com.informatimago.common-lisp.picture
Quicklisp

インストール方法

(ql:quickload :com.informatimago.common-lisp.picture)

で対象のライブラリのみ。または、

(ql:quickload :com.informatimago.common-lisp)

で他のライブラリも一緒に読み込めます。

試してみる

 comp.lang.lispでは色々な質問の回答者としてお馴染のPascal Bourguignon氏ですが、com.informatimago.common-lispというライブラリ集を作っていて、様々なものが収められています。
今回紹介するcom.informatimago.common-lisp.pictureは2つのパッケージから構成されていますが、picutureの方は汎用のアスキーアートのライブラリで、cons-to-asciiはコンスセルのアスキーアートを作成するライブラリです。

(defvar *tree* '(-9 (-2 (9 10))))
*tree*
;=>  (-9 (-2 (9 10)))

(use-package '(:com.informatimago.common-lisp.picture.cons-to-ascii :com.informatimago.common-lisp.picture.picture))

(draw-list *tree*) ;=> +-----------------------------------------------+ ; | (-9 (-2 (9 10))) | ; | | ; | +---+---+ +---+---+ | ; | | * | * |-->| * |NIL| | ; | +---+---+ +---+---+ | ; | | | | ; | v v | ; | +----+ +---+---+ +---+---+ | ; | | -9 | | * | * |-->| * |NIL| | ; | +----+ +---+---+ +---+---+ | ; | | | | ; | v v | ; | +----+ +---+---+ +---+---+ | ; | | -2 | | * | * |-->| * |NIL| | ; | +----+ +---+---+ +---+---+ | ; | | | | ; | v v | ; | +---+ +----+ | ; | | 9 | | 10 | | ; | +---+ +----+ | ; +-----------------------------------------------+ ;

(let ((p (frame-rect (make-instance 'picture :width 72 :height 30 :background ".") 0 0 74 30))) (draw-cell p 2 25 *tree*)) ;=> +----------------------------------------------------------------------- ; |....................................................................... ; |....................................................................... ; |....................................................................... ; |.+---+---+...+---+---+................................................. ; |.| * | * |-->| * |NIL|................................................. ; |.+---+---+...+---+---+................................................. ; |...|...........|....................................................... ; |...v...........v....................................................... ; |.+----+......+---+---+...+---+---+..................................... ; |.|.-9.|......| * | * |-->| * |NIL|..................................... ; |.+----+......+---+---+...+---+---+..................................... ; |...............|...........|........................................... ; |...............v...........v........................................... ; |.............+----+......+---+---+...+---+---+......................... ; |.............|.-2.|......| * | * |-->| * |NIL|......................... ; |.............+----+......+---+---+...+---+---+......................... ; |...........................|...........|............................... ; |...........................v...........v............................... ; |.........................+---+.......+----+............................ ; |.........................|.9.|.......|.10.|............................ ; |.........................+---+.......+----+............................ ; |....................................................................... ; |....................................................................... ; |....................................................................... ; |....................................................................... ; |....................................................................... ; |....................................................................... ; |....................................................................... ; +----------------------------------------------------------------------- ;

(let ((p (frame-rect (make-instance 'picture :width 35 :height 20 :background ".") 0 0 80 30))) (draw-string p 0 0 "0") (draw-string p 10 0 "10") (draw-string p 20 0 "20") (draw-string p 30 0 "30") (draw-line p 0 0 10 10) (draw-line p 10 10 10 -5) (draw-line p 20 5 10 10) (draw-line p 30 15 10 -10) (draw-arrow p 23 15 5 0)) ;=> |.................................. ; |.................................. ; |.................................. ; |.................................. ; |......................----->.*.... ; |............................*.*... ; |...........................*...*.. ; |..........................*.....*. ; |.........................*.......* ; |.........**.............*......... ; |........*..**..........*.......... ; |.......*.....**.......*........... ; |......*........**....*............ ; |.....*...........**.*............. ; |....*..............*.............. ; |...*.............................. ; |..*............................... ; |.*................................ ; |*................................. ; *---------10--------20--------30--- ;

まとめ

 今回は、com.informatimago.common-lisp.pictureを紹介してみました。
Pascal Bourguignon氏は面白いものを沢山作っていますので、どんどん紹介していきたいと思っています。

draw-cons-treeの紹介

Posted 2014-10-26 15:00:00 GMT

(LISP Library 365参加エントリ)

 LISP Library 365 の300日目です。

draw-cons-treeとはなにか

 draw-cons-treeは、コンスのツリーをアスキーアートで表示するものです。Nils M. Holm氏がSchemeで作成したものをChris Bagley氏がCommon Lispに移植したものとのこと。

パッケージ情報

パッケージ名draw-cons-tree
Quicklisp
Quickdocsdraw-cons-tree | Quickdocs
CL Test Grid: ビルド状況draw-cons-tree | CL Test Grid

インストール方法

(ql:quickload :draw-cons-tree)

試してみる

 どんな関数があるかは、Quickdocsで確認できます。

 エクスポートされている定義は、draw-cons-treeのみです。

(defvar *tree* (funcall (5am:gen-tree :size 5)))

*tree* ;=> (-9 (-2 (9 10)))

(draw-cons-tree:draw-tree *tree*) ;>> [o|o]---[o|/] ;>> | | ;>> -9 [o|o]---[o|/] ;>> | | ;>> -2 [o|o]---[o|/] ;>> | | ;>> 9 10 ;>> ;=> NIL

こんな感じにコンスセルの木がアスキーアートになります。

まとめ

 今回は、draw-cons-treeを紹介してみました。
コンパクトな表示でなかなか良いですね。

Emacs Lisp: nadviceの紹介

Posted 2014-10-25 15:00:00 GMT

(LISP Library 365参加エントリ)

 LISP Library 365 の299日目です。

Emacs Lisp: nadviceとはなにか

 Emacs Lisp: nadviceは、

パッケージ情報

パッケージ名Emacs Lisp: nadvice
Emacs LispマニュアルAdvising Functions - GNU Emacs Lisp Reference Manual

インストール方法

 Emacs 24.4から使える機能で、nadvice.elで定義されています。

試してみる

 これまで色々な処理系でアドバイス機構を紹介してきましたが、今回も同様に、

(defun matu (x)
  (princ (format ">>%s<<\n" x))
  nil)     

(matu 8) ;>> >>8<< ;=> nil

のような関数があったとすると、

;>> around1 ==>
;>> around0 ==>
;>> before1:
;>> before0:
;>> >>8<<
;>> after0: 
;>> after1: 
;>> around0 <== 
;>> around1 <== 
;=> NIL

のような結果を得るには、

(defun matu-around0 (f &rest args)
  (prog2
    (princ "around0 ==>\n")
    (apply f args)
    (princ "around0 <==\n")))

(defun matu-around1 (f &rest args) (prog2 (princ "around1 ==>\n") (apply f args) (princ "around1 <==\n")))

(defun matu-before0 (&rest args) (princ "before0:\n"))

(defun matu-before1 (&rest args) (princ "before1:\n"))

(defun matu-after0 (&rest args) (princ "after0:\n"))

(defun matu-after1 (&rest args) (princ "after1:\n"))

(advice-add 'matu :before #'matu-before0) (advice-add 'matu :before #'matu-before1) (advice-add 'matu :after #'matu-after0) (advice-add 'matu :after #'matu-after1) (advice-add 'matu :around #'matu-around0) (advice-add 'matu :around #'matu-around1)

こんな感じの定義と定義順になります。定義順に内側から外側へ付加されていきますが、オプションのalistのdepth属性で制御することが可能です。-100から100までで-100が最も外側とのこと。デフォルトは0。
ということで上記を定義順は関係なく同様の構成にしたい場合は、

(advice-add 'matu :around #'matu-around0 '((depth . -2)))
(advice-add 'matu :around #'matu-around1 '((depth . -2)))
(advice-add 'matu :before #'matu-before0 '((depth . 0)))
(advice-add 'matu :before #'matu-before1 '((depth . -1)))
(advice-add 'matu :after #'matu-after0 '((depth . 0)))
(advice-add 'matu :after #'matu-after1 '((depth . -1)))

のようになるかと思います。
アドバイスの削除は、advice-removeで

(advice-remove 'matu #'matu-around1)

のようにしますが、名前付き関数を指定していることから分かるように無名関数でアドバイスを付けてしまうと取り外しが面倒なことになります。

before/after/around以外の仲間達

 定番のbefore/after/around以外にも7つ程パタンが増えたみたいです。
どういう挙動になるかは、add-functionのドキュメンテーションストリングを読む方が早いかもしれませんが、

`:before'	(lambda (&rest r) (apply FUNCTION r) (apply OLDFUN r))
`:after'	(lambda (&rest r) (prog1 (apply OLDFUN r) (apply FUNCTION r)))
`:around'	(lambda (&rest r) (apply FUNCTION OLDFUN r))
`:override'	(lambda (&rest r) (apply FUNCTION r))
`:before-while'	(lambda (&rest r) (and (apply FUNCTION r) (apply OLDFUN r)))
`:before-until'	(lambda (&rest r) (or  (apply FUNCTION r) (apply OLDFUN r)))
`:after-while'	(lambda (&rest r) (and (apply OLDFUN r) (apply FUNCTION r)))
`:after-until'	(lambda (&rest r) (or  (apply OLDFUN r) (apply FUNCTION r)))
`:filter-args'	(lambda (&rest r) (apply OLDFUN (funcall FUNCTION r)))
`:filter-return'(lambda (&rest r) (funcall FUNCTION (apply OLDFUN r)))

適当に試してみると下記のような感じです。

(defun foo (n) n)

(list (foo 0) (foo 42)) ;=> (0 42)

(advice-add 'foo :override #'zerop)

(list (foo 0) (foo 42)) ;=> (t nil)

(advice-remove 'foo #'zerop)

(advice-add 'foo :before-while #'zerop) ;=> nil

(list (foo 0) (foo 42)) ;=> (0 nil) (advice-remove 'foo #'zerop) ;=> nil

(advice-add 'foo :before-until #'zerop) ;=> nil

(list (foo 0) (foo 42)) ;=> (t 42)

(advice-remove 'foo #'zerop) ;=> nil

(advice-add 'foo :after-while #'zerop) ;=> nil

(list (foo 0) (foo 42)) ;=> (t nil)

(advice-remove 'foo #'zerop) ;=> nil

(advice-add 'foo :after-until #'zerop) ;=> nil

(list (foo 0) (foo 42)) ;=> (0 42)

(advice-remove 'foo #'zerop) ;=> nil

(advice-add 'foo :filter-return #'1+) ;=> nil

(foo 1) ;=> 2

(defun bar (&rest args) (length args))

(bar 1 2 3) ;=> 3

(advice-add 'bar :filter-args #'print)

(bar 1 2 3) ;>> (1 2 3) ;=> 3

メソッド結合でいうとandやorみたいなものが追加された感じですね。
ちなみにadvice-add、advice-removeは、それぞれよりプリミティブなadd-function、remove-functionを呼び出しています。これらの詳細はマニュアルを参照してください。

まとめ

 今回は、Emacs Lisp: nadviceを紹介してみました。
新しい方式は、普通の関数呼び出しの合成という感じなので、馴染み易いかもしれないですね。

cl-difflibの紹介

Posted 2014-10-23 15:00:00 GMT

(LISP Library 365参加エントリ)

 LISP Library 365 の297日目です。

cl-difflibとはなにか

 cl-difflibは、John Wiseman氏作のPythonのdifflibのCommon Lisp版です。

パッケージ情報

パッケージ名cl-difflib
Quicklisp
CLiKiCLiki: CL-DIFFLIB
Quickdocscl-difflib | Quickdocs
CL Test Grid: ビルド状況cl-difflib | CL Test Grid

インストール方法

(ql:quickload :cl-difflib)

試してみる

 どんな関数があるかは、Quickdocsで確認できます。

 Pythonのdifflibそのままの名前ではありませんが、大体対応するものは同じ名前になっているようです。

に対応するのは、大体

  • context-diff
  • get-close-matches
  • get-opcodes
  • group-opcodes
  • sequence-matcher
  • quick-similarity-ratio
  • unified-diff
  • very-quick-similarity-ratio

位でしょうか。

(difflib:unified-diff *standard-output*
                      '("one" "two" "three" "four" "five" "six")
                      '("one" "three" "four" "seven" "six")
                      :test-function #'equal)
;>>  ---  
;>>  +++  
;>>  @@ -1,6 +1,5 @@
;>>   one
;>>  -two
;>>   three
;>>   four
;>>  -five
;>>  +seven
;>>   six
;=>  <no values>

(difflib:context-diff *standard-output* '("one" "two" "three" "four" "five" "six") '("one" "three" "four" "seven" "six") :test-function #'equal) ;>> *** ;>> --- ;>> *************** ;>> *** 1,6 *** ;>> one ;>> - two ;>> three ;>> four ;>> ! five ;>> six ;>> --- 1,5 ---- ;>> one ;>> three ;>> four ;>> ! seven ;>> six ;=> <no values>

(difflib:get-close-matches (string 'multiple-value-bind) (mapcar #'string (*:list-external-symbols :alexandria))) ;=> ("MULTIPLE-VALUE-PROG2" "MULTIPLE-VALUE-COMPOSE")

(difflib:get-close-matches (string 'list) (mapcar #'string (*:list-external-symbols :alexandria))) ;=> ("DOPLIST")

(difflib:quick-similarity-ratio (make-instance 'difflib:sequence-matcher :a "abcd" :b "bcde" :test-function #'equal)) ;=> 3/4

使い方も大体同じです。

まとめ

 今回は、cl-difflibを紹介してみました。
他の言語のライブラリをCommon Lispに移植したものの一覧もいつか作ってみたいですね。

Emacs 24.4でskk + slime + pareditの競合を回避

Posted 2014-10-23 04:30:00 GMT

 前に書いた、skk + slime + pareditの競合をアドバイスで回避する方法ですが、

slimeがlexical-binding: tで書かれるようになった所為か、elispのdefadviceのad-arglistあたりとの組み合わせがどうも良くない感じになっていました。
どうもアドバイスの方はダイナミックスコープで動作している様子でarglistの参照がすっぽ抜けます。
Emacs 24.4でアドバイスが新しい方式に変わったとのことで、もしかしたらこの辺りが解決されているのかなと思って試してみました。
ざっと書いてみたところ、

;; -*-lexical-binding:t-*-
(require 'skk)
(require 'skk-azik)
(require 'paredit)
(require 'slime)

;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;; paredit & skk ;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;

(defun paredit-semicolon\\skk-kakutei (origfun &rest arglist) "skk-azikで ?; で「っ」を出している場合に競合するのを回避" (apply (cond (skk-j-mode ;; skk-modeでかな入力(mode-lineに「かな/カナ」とある状態)の場合 ;; skk-insertへ処理を投げる #'skk-insert) (t ;; それ以外は、通常のparedit-semicolon origfun)) arglist))

(advice-add 'paredit-semicolon :around #'paredit-semicolon\\skk-kakutei) ;; (advice-add 'paredit-semicolon #'paredit-semicolon\\skk-kakutei)

(defun paredit-open-square\\skk-insert (origfun &rest arglist) "skkのカナ/かな切り替えが[になってしまうのを回避" (apply (cond (skk-j-mode ;; skk-modeでかな入力(mode-lineに「かな/カナ」とある状態)の場合 ;; skk-insertへ処理を投げる #'skk-insert) (t ;; それ以外は、通常のparedit-open-square origfun)) arglist))

(advice-add 'paredit-open-square :around #'paredit-open-square\\skk-insert) ;; (advice-remove 'paredit-open-square #'paredit-open-square\\skk-insert)

(defun paredit-newline\\skk-kakutei (origfun &rest arglist) "skk-mode時に かな→asciiの一方通行になってしまうのを回避" (apply (cond ((not skk-mode) ;; skk-modeでなければparedit-newlineの動作で良い origfun) (t ;; skk-modeでは、skk-kakuteiで、skk-j-modeへ入る #'skk-kakutei)) arglist))

(advice-add 'paredit-newline :around #'paredit-newline\\skk-kakutei) ;; (advice-remove 'paredit-newline #'paredit-newline\\skk-kakutei)

;;;;;;;;;;;;;;;;;;;;;;; ;;;;; slime & skk ;;;;; ;;;;;;;;;;;;;;;;;;;;;;;

(defun slime-space\\skk-insert (origfun &rest arglist) "skkの変換(スペース)がslime-spaceに食われてしまうのを回避" (apply (cond (skk-henkan-mode ;; skk-henkan-mode中であれば(▽▼の時)skk-insertへ処理を投げる #'skk-insert) (t ;; それ以外は通常のslime-space origfun)) arglist))

(advice-add 'slime-space :around #'slime-space\\skk-insert) ;; (advice-remove 'slime-space #'slime-space\\skk-insert)

;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;; slime-repl & skk ;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;

(defun slime-handle-repl-shortcut\\skk-insert (origfun &rest arglist) "slime-replで「、」が「,」になるのを回避" (cond (skk-j-mode (insert "、")) (t (apply origfun arglist))))

(advice-add 'slime-handle-repl-shortcut :around #'slime-handle-repl-shortcut\\skk-insert) ;; (advice-remove 'slime-handle-repl-shortcut #'slime-handle-repl-shortcut\\skk-insert)

(defun slime-repl-newline-and-indent\\skk-kakutei (origfun &rest arglist) "slime-replで確定動作が改行になるのを回避" (apply (cond ((not skk-mode) ;; skk-modeでなければparedit-newlineの動作で良い origfun) (t ;; skk-modeでは、skk-kakuteiで、skk-j-modeへ入る #'skk-kakutei)) arglist))

(advice-add 'slime-repl-newline-and-indent :around #'slime-repl-newline-and-indent\\skk-kakutei) ;; (advice-remove 'slime-repl-newline-and-indent :around #'slime-repl-newline-and-indent\\skk-kakutei)

という感じになりました。
方式がシンプルに関数の組み合わせになったので書くのも楽といえば楽。
スコープ方式が入り乱れた場合のarglistのスコープの問題も関数の入れ子になるので解決かなと思われます。
なお、同じパタンが何度か出ているのでまとめようかなとも思いましたが、まとめるのが面倒だったのでベタ書きしています。

cl-qprintの紹介

Posted 2014-10-22 15:00:00 GMT

(LISP Library 365参加エントリ)

 LISP Library 365 の296日目です。

cl-qprintとはなにか

 cl-qprintは、Robert Marlow氏とMax Rottenkolber氏によるRFC 2045のQuoted-Printableを扱うライブラリです。

パッケージ情報

パッケージ名cl-qprint
Quicklisp
CLiKiCLiki: cl-qprint
Quickdocscl-qprint | Quickdocs
CL Test Grid: ビルド状況cl-qprint | CL Test Grid

インストール方法

(ql:quickload :cl-qprint)

試してみる

 どんな関数があるかは、Quickdocsで確認できます。

 内容はシンプルにencodeとdecodeのみ。
入力にはオクテットかオクテットのストリームが使えます。

(qprint:encode (*:string-to-octets "Now's the time for all folk to come to the aid of their country."))
;=>  "Now's=20the=20time=20for=20all=20folk=20to=20come=20to=20the=20aid=20of=20th=^M
;    eir=20country."

(qprint:decode (qprint:encode (map 'vector #'char-code "Now's the time for all folk to come to the aid of their country."))) ;=> #(78 111 119 39 115 32 116 104 101 32 116 105 109 101 32 102 111 114 32 97 108 ; 108 32 102 111 108 107 32 116 111 32 99 111 109 101 32 116 111 32 116 104 101 ; 32 97 105 100 32 111 102 32 116 104 101 105 114 32 99 111 117 110 116 114 121 ; 46)

(with-open-stream (in (*:make-byte-array-input-stream (*:string-to-octets "Now's the time for all folk to come to the aid of their country."))) (qprint:encode in)) ;=> "Now's=20the=20time=20for=20all=20folk=20to=20come=20to=20the=20aid=20of=20th=^M ; eir=20country."

(with-open-stream (in (*:make-byte-array-input-stream (*:string-to-octets "おはよう日本おはよう日本おはよう日本"))) (qprint:encode in)) ;=> "=E3=81=8A=E3=81=AF=E3=82=88=E3=81=86=E6=97=A5=E6=9C=AC=E3=81=8A=E3=81=AF=E3=^M ; =82=88=E3=81=86=E6=97=A5=E6=9C=AC=E3=81=8A=E3=81=AF=E3=82=88=E3=81=86=E6=97=^M ; =A5=E6=9C=AC"

(*:octets-to-string (qprint:decode (qprint:encode (*:string-to-octets "おはよう日本おはよう日本おはよう日本")))) ;=> "おはよう日本おはよう日本おはよう日本"

まとめ

 今回は、cl-qprintを紹介してみました。
一発物は紹介が楽です。

cl-cronの紹介

Posted 2014-10-21 15:00:00 GMT

(LISP Library 365参加エントリ)

 LISP Library 365 の295日目です。

cl-cronとはなにか

 cl-cronは、Mackram Ghassan Raydan氏作のCommon Lispでのcron実装です。

パッケージ情報

パッケージ名cl-cron
Quicklisp
CLiKiCLiki: cl-cron
Quickdocscl-cron | Quickdocs
CL Test Grid: ビルド状況cl-cron | CL Test Grid

インストール方法

(ql:quickload :cl-cron)

試してみる

 どんな関数があるかは、Quickdocsで確認できます。

 Lisp処理系でcron的なものを実現したものは幾つかあるようなのですが、cl-cronは処理系内部からLispの関数を実行するタイプのようです。

(cron:start-cron)

(cron:stop-cron)

で実行開始/停止で、ジョブの投入には、make-cron-jobを利用します。

(cron:make-cron-job (lambda () (print "hello")))

とすれば、毎分helloを出力するジョブが投入されます。実行時刻の指定は大体cronと同じです。

start-cronは、起動時にcron:*cron-load-file*で指定したファイルを読みに行くので、このファイルにジョブを記載しておけばまとめてジョブを投入できます。

(setq cron:*cron-load-file* "~/.cl-cron")

として、~/.cl-cronに、

;;; 毎時の0、15、30、45で実行
(cron:make-cron-job (lambda () (print "hello"))
                    :minute '(0 15 30 45)) 

;;; 毎週月曜の0:00に実行 (cron:make-cron-job (lambda () (print "hello")) :minute 0 :hour 0 :day-of-week 0)

;;; 毎分実行 (cron:make-cron-job (lambda () (print "hello")))

;;; *EOF*

のようなものを定義して利用することが可能です。

まとめ

 今回は、cl-cronを紹介してみました。
Common Lisp製のデーモンかなにかの中で定期実行したい場合に便利そうですね。

Older entries (1819 remaining)