MacでSticky ShiftにするためのKarabinerの設定
SKKを使いはじめました.
そうするとシフトキーを多用するのでもっと楽に入力したくなります.
そこでSticky Shiftです.
「シフトキーを押したまま他のキーを入力する」のではなく,「一度シフトキーを押して離した直後に押したキーが大文字になってくれます.
SKKを使っていなくてもCamelCaseなどの入力がとても楽になります.
左手小指はControlキーのためにありますからね.
全国一千万人のEmacs愛好家にとっては譲れませんよね.
Karabinerに標準でSticky Shiftの設定項目はありませんが,private.xmlを編集することで設定できるようになります.
ただ private.xml
の記述方法がわかりづらかったので書いておきます.
僕はセミコロンをSticky Shiftにして右シフトをセミコロンにしています.
そのかわりに右シフトをセミコロンに当てています.
~/Library/Application\ Support/Karabiner/private.xmlを編集します.
<?xml version="1.0"?> <root> <item> <name>Common</name> <item> <name>Sticky Shift</name> <appendix>Use semicolon to Sticky Shift_L</appendix> <identifier>private.semicolon_to_sticky_shift_l</identifier> <autogen> --KeyToKey-- KeyCode::SEMICOLON, ModifierFlag::NONE, KeyCode::VK_STICKY_SHIFT_L </autogen> </item> <item> <name>Change Shift_R2Semicoron</name> <appendix>Use Shift_R to Semicolon</appendix> <identifier>private.dhift_r_to_semicolon</identifier> <autogen>--KeyToKey-- KeyCode::SHIFT_R, KeyCode::SEMICOLON</autogen> </item> </item> </root>
これでKarabinerでSticky Shiftをチェックできるようになります.
SKKを使っていなくてもSticky Shiftは便利なので是非設定しましょう.
Railsのnew/build/createの違い
build - リファレンス - - Railsドキュメント
new
モデルオブジェクトを生成する.
生成するだけで,保存はされていないためsaveメソッドなどを使用して保存する.
build
new の alias
create
モデルオブジェクトを生成して保存する.
リモートのブランチにローカルでチェックアウトする
まずリモートブランチをfetchします.
$ git fetch
次にリモートブランチを確認します.
$ git branch -a * master remotes/origin/01_untested remotes/origin/02_setup remotes/origin/03_models remotes/origin/04_factories remotes/origin/05_controller_basics remotes/origin/06_advanced_controllers remotes/origin/07_controller_cleanup remotes/origin/08_features remotes/origin/09_speedup remotes/origin/11_tdd remotes/origin/HEAD -> origin/master remotes/origin/master
ここでチェックアウトしたいのは02_setup
です.
ローカルブランチ名を指定してリモートブランチをチェックアウトします.
$ git co -b 02_setup origin/02_setup Branch 02_setup set up to track remote branch 02_setup from origin. Switched to a new branch '02_setup'
これでリモートブランチにチェックアウトすることができました.
Scheme修行のtryについて
- 作者: Daniel P. Friedman and Matthias Felleisen,元吉文男,横山晶一
- 出版社/メーカー: オーム社
- 発売日: 2011/06/15
- メディア: 単行本(ソフトカバー)
- 購入: 3人 クリック: 46回
- この商品を含むブログ (10件) を見る
p89の欄外で補足されているtryについて.
これが出てきたのは rember1*
の実装の中です.
rember1*
はatom aとリストlを引数に取ります.
lの中で最初に出てきたaと同じアトムを削除して新しいリストを返す手続きです.
tryを使う前の実装は以下になります.
(define rember1* (lambda (a l) (if (atom? (let/cc oh (rm a l oh))) l (rm a l (quote ()))))) (define rm (lambda (a l oh) (cond ((null? l) (oh (quote no))) ((atom? (car l)) (if (eq? (car l) a) (cdr l) (cons (car l) (rm a (cdr l) oh)))) (else (let ((new-car (let/cc oh (rm a (car l) oh)))) (if (atom? new-car) (cons (car l) (rm a (cdr l) oh)) (cons new-car (cdr l))))))))
リストの中で最後まで探し終わってlがnullになれば継続に(quote no)
を渡します.
atomであればcarにリストはないのでcdrを探します.
再帰的に探して,aと同じものがあれば,それを取り除いた残りのリストを返します.
取り除くのは最初に見つかったものだけです.
このコードをtryを使うとこうなります.
(define rember1* (lambda (a l) (try oh (rm a l oh) l))) (define rm (lambda (a l oh) (cond ((null? l) (oh (quote no))) ((atom? (car l)) (if (eq? (car l) a) (cdr l) (cons (car l) (rm a (cdr l) oh)))) (else (try oh2 (cons (rm a (car l) oh2) (cdr l)) (cons (car l) (rm a (cdr l) oh)))))))
tryについてはここでページ欄外に
(try x α β) = (let/cc success (let/cc x (success a)) b)
と書かれています.
ここがなかなかわかりませんでした.
まず中のlet/ccから考えます.
(let/cc x (success α))
α内で継続xが使われているはずです.
継続xに値γが渡されると,(let/cc x γ)
となり,次の計算βに進みます.
継続xに値が渡されない場合はαの値が継続successに渡され,そこで計算が終了しこの式の値はαとなります.
つまり,tryはα内で継続xに値が渡されればβの値が返り,
渡されなければαの値が返るわけです.
元の式で継続に値が渡されたのを判別するために(quote no)
を継続に渡してatom?で判別していたものを
継続が返ってくるかこないかで判別できるようになっています.
継続難しいです.
でもScheme修行で少しずつわかってきた気がします.
Schemeでクイックソート
先日の納会でソートの話が少し出たのでクイックソートを書いてみました.
書きやすいのでGaucheで.
まず普通に書いてみます.
(define (quick lst) (if (null? lst) '() (let ((first (car lst))) (append (quick (filter (lambda (x) (< x first)) lst)) (filter (lambda (x) (= x first)) lst) (quick (filter (lambda (x) (< first x)) lst))))))
gosh> (quick '( 4 7 8 3 9 2 7 3 92 7 1)) (1 2 3 3 4 7 7 7 8 9 92)
普通ですね.
ただfilterで何度もリストの中身を舐めているのが嫌です.
ここでstreamを使ってみます.
(use util.stream) (define (quick lst) (stream->list (let recur ((s (list->stream lst))) (if (stream-null? s) stream-null (let ((first (stream-car s))) (stream-append (recur (stream-filter (lambda (x) (< x first)) s)) (stream-filter (lambda (x) (= x first)) s) (recur (stream-filter (lambda (x) (< first x)) s))))))))
gosh> (quick '( 4 7 8 3 9 2 7 3 92 7 1)) (1 2 3 3 4 7 7 7 8 9 92)
リストからストリームへの変換とストリームからリストへの変換が入っているので
効率的になったのかどうか怪しいですが一応期待通りに動いていますね.
どうするのが正解なんでしょう?
once-onlyマクロの解読
実践Common Lisp p100にあるonce-onlyマクロの解読に挑戦.
- 作者: Peter Seibel,佐野匡俊,水丸淳,園城雅之,金子祐介
- 出版社/メーカー: オーム社
- 発売日: 2008/07/26
- メディア: 単行本(ソフトカバー)
- 購入: 8人 クリック: 192回
- この商品を含むブログ (69件) を見る
マクロのコードは以下のとおり.
(defmacro onece-only ((&rest names) &body body) (let ((gensyms (loop for n in names collect (gensym)))) `(let (,@ (loop for g in gensyms collect `(,g (gensym)))) `(let (,,@ (loop for g in gensyms for n in names collect ``(,,g ,,n))) ,(let (,@ (loop for n in names for g in gensyms collect `(,n ,g))) ,@body)))))
一行ずつ解読していく
まずは
(let ((gensyms (loop for n in names collect (gensym))))
の部分から.
バッククォートがないので何がgensymsに束縛されるかをREPLで確かめる.
CL-USER> (let ((gensyms (loop for n in '(a b c) collect (gensym)))) gensyms) (#:G884 #:G885 #:G886)
namesの数と同じだけのユニークなシンボルを作成している.
次の行は
`(let (,@ (loop for g in gensyms collect `(,g (gensym))))
gensymsは一行目の処理でユニークなシンボルのリストになっている.
gensymsのそれぞれの要素と(gensym)をペアにしていく.
ここまでを実行してみる.
CL-USER> (let ((gensyms (loop for n in '(a b c) collect (gensym)))) `(let (,@ (loop for g in gensyms collect `(,g (gensym)))))) (LET ((#:G887 (GENSYM)) (#:G888 (GENSYM)) (#:G889 (GENSYM))) )
三行目.
`(let (,,@ (loop for g in gensyms for n in names collect ``(,,g ,,n)))
とうとう`,が二重に.
1つずつ見ていく.
二行目の`(let の式の中で `(letとなっているのでここは出力後の形が`(letとなってほしいはず.
,,@となっているのは二行目のバッククォート,三行目頭のバッククォートと二回バッククォートされているので
二度展開しなといloopが展開されない.
これでloop内は展開されるようになった.
次は``(,,g ,,n).二重にバッククォートするのは先ほどと同じように`(foo bar) という形のリストにしたいから.
(,,g ,,n)になっているのはloopでgensymsの要素をgに,namesの要素をnに対応付けているから.
`(,gensymsの要素 ,nameの要素)という形に変換しようとしている.
ここまでを展開するとこうなる
CL-USER> (let ((names '(a b c))) (let ((gensyms (loop for n in names collect (gensym)))) `(let (,@(loop for g in gensyms collect `(,g (gensym)))) `(let (,,@ (loop for g in gensyms for n in names collect ``(,,g ,,n))) )))) (LET ((#:G937 (GENSYM)) (#:G938 (GENSYM)) (#:G939 (GENSYM))) `(LET (,`(,#:G937 ,A) ,`(,#:G938 ,B) ,`(,#:G939 ,C)) ))
コンパイル時には新たに(gensym)で作られたユニークなシンボルにnamesの値が束縛されるようになる.
最後に4行目.
,(let (,@ (loop for n in names for g in gensyms collect `(,n ,g)))
二行目と三行目でバッククォートされてるので,先頭のカンマは展開されず(let ...という形になる.
,@の部分は既に先頭で一度カンマがあった後なのでそのまま展開出来る.
`(,n ,g)の部分で実際にAにAの値を束縛するという部分を作る.
なのでここではバッククォートが一つ.
ここのgには3行目で値に束縛したユニークなシンボルが入る.
実際に展開する.
最後なのですべて展開するとこうなる.
CL-USER> (let ((names '(a b c)) (body '(body))) (let ((gensyms (loop for n in names collect (gensym)))) `(let (,@(loop for g in gensyms collect `(,g (gensym)))) `(let (,,@ (loop for g in gensyms for n in names collect ``(,,g ,,n))) ,(let (,@ (loop for n in names for g in gensyms collect `(,n ,g))) ,@body))))) (LET ((#:G934 (GENSYM)) (#:G935 (GENSYM)) (#:G936 (GENSYM))) `(LET (,`(,#:G934 ,A) ,`(,#:G935 ,B) ,`(,#:G936 ,C)) ,(LET ((A #:G934) (B #:G935) (C #:G936)) BODY)))
まとめ
まずnamesと同じ数だけ(gensym)でユニークなシンボルを作り,それをgensymsというリストにする.
gensymsの各要素を新たに(gensym)に束縛するlet式を作る.
この(gensym)はonce-onlyを使うマクロの展開時に新しくユニークなシンボルを作る.
gensymsの各要素を評価すると新しく作られるユニークなシンボルを返すようになる.
このユニークなシンボルにnamesの各値を束縛するようにする.
それが本体の三行目に当たる.
四行目ではnamesのシンボルにgensymsの各要素を対応付ける.
gensymsの各要素は新たに作られたユニークなシンボルに束縛され,そのユニークなシンボルはnameの値に束縛される.
以上で終わり.
高階マクロで名前の衝突を回避して,評価順序を保つのはこんなに大変なんですね.
shibuya.lispで発表しました
ゆるわな感じです.
Lisp Meet Up presented by Shibuya.lisp #38 - connpass
反省点は聞いてる人のほうを向いて喋れなかったことですね. 自分のPCのモニタばかり見てました. 次どこかで発表するときはそこを改善したいですね. 後もっとましなスライドを作れるようになりたい.
- 作者: ハロルドエイブルソン,ジュリーサスマン,ジェラルド・ジェイサスマン,Harold Abelson,Julie Sussman,Gerald Jay Sussman,和田英一
- 出版社/メーカー: 翔泳社
- 発売日: 2014/05/17
- メディア: 大型本
- この商品を含むブログ (2件) を見る