:ls
と入力する。
開いているバッファの一覧とパスが表示される。
]]>     remote           refid      st t when poll reach   delay   offset  jitter
==============================================================================
*tok-ntp-ext.asi 17.82.254.14     2 u  576 1024  377   12.519    3.781   2.018
reachに表示されている値は8進数で、1ビットごとにNTPサーバへpollした際の成否を表している。
LSBから順に前回、前々回……と8回前のpollまで成否がわかる。
例えば、前々回のpollが失敗し、それ以外は成功した場合、reachは (11111101)_2 = (375)_8 となる。
]]>user=> (filter (comp not nil?) '(a nil b nil c nil d)) (a b c d)]]>
(= nil '()) => false
よって、再帰の停止条件などでは空リストか否かを返す述語 empty? を使う。
  (defn sum [lst]
    (if (empty? lst)
      0
      (+ (first lst) (sum (rest lst)))))
]]>% sl
と入力した後で、Ctrl-tを入力すると、
% ls
となる。
]]>ghci> (6, 2) `canReachIn3` (6, 1) True
のように始点と終点を指定すると到達の可否がかえってくる。
節尾の演習にどのように到達できるか教えてくれるようにせよとあったので書いてみる。
import Monad
type KnightPos = (Int, Int)
type KnightTrack = [KnightPos]
moveKnight :: KnightTrack -> [KnightTrack]
moveKnight ((c, r) : xs)  = 
  map addLog $
  filter onBoard [(c+2,r-1), (c+2,r+1), (c-2,r-1), (c-2,r+1)
                 ,(c+1,r-2), (c+1,r+2), (c-1,r-2), (c-1,r+2)]
  where onBoard (c, r) = c `elem` [1..8] && r `elem` [1..8]
        addLog pos = pos : (c, r) : xs
in3 :: KnightTrack -> [KnightTrack]
in3 start = return start >>= moveKnight >>= moveKnight >>= moveKnight
canReachIn3 :: KnightPos -> KnightPos -> [KnightTrack]
canReachIn3 start end = 
  filter (\(pos : track) -> pos == end) $ in3 [start]
canReachIn3は真偽値でなくナイトの軌跡を返すように変更した。到達できないときは [] が帰る。
ghci>canReachIn3 (6,2) (6,1) [[(6,1),(7,3),(8,1),(6,2)],[(6,1),(5,3),(4,1),(6,2)],[(6,1),(5,3),(7,4),(6,2)], [(6,1),(8,2),(7,4),(6,2)],[(6,1),(7,3),(5,4),(6,2)],[(6,1),(4,2),(5,4),(6,2)]] ghci>canReachIn3 (6,2) (7,3) []]]>
随時更新.
| Common Lisp | Scheme | 備考 | 
|---|---|---|
| atom | なし | (not (pair? obj))を使う | 
| consp | pair? | |
| dolist | for-each | 記法は異なる | 
| mapcan | append-map! | SRFI 1 | 
| mapcar | map | |
| multiple-value-bind | receive | SRFI 8, library syntax | 
| null | null? | |
| nth | list-ref | |
| nthcdr | list-tail | SRFI 1ではdrop | 
| progn | begin | |
| rplaca | set-car! | |
| rplacd | set-cdr! | |
| setq | set! | 
rlwrapはreadlineを使用していないプログラムでもreadlineが使えるように入力をラップするコマンド。
http://utopia.knoware.nl/~hlub/rlwrap/
から入手できる。FreeBSDではportsにあった。
特にLispのREPLではカッコの対応がすぐわかってうれしい。
]]>mutexやcondition variableのような同期機構ではなく、チャネル通信などの機構を使えということなのだと思うが、ロックを使ったほうが素直に実装できる場合もある。
幸いセマフォはあるようなので、セマフォでmutexやcondition variableを次のように書いた。
;;; mutex
(define (make-mutex)
  (make-semaphore 1))
(define (mutex-lock! m)
  (semaphore-wait m))
(define (mutex-unlock-primitive! m)
  (semaphore-post m))
(define (mutex-unlock! m . rest)
  (let ((condvar (if (null? rest) #f (car rest))))
    (mutex-unlock-primitive! m)
    (when condvar
      (condition-variable-wait! condvar))))
;;; gate
(define (make-gate)
  (make-semaphore 0))
(define (gate-wait! g)
  (semaphore-wait g))
(define (gate-signal! g)
  (semaphore-post g))
;;; condition variable
(define (make-condition-variable)
  (list 'condition-variable '() (make-mutex)))
(define (condition-variable-gates cv)
  (list-ref cv 1))
(define (condition-variable-mutex cv)
  (list-ref cv 2))
(define (condition-variable-clear-gates! cv)
  (set-car! (cdr cv) '() ))
(define (condition-variable-put-gates! cv val)
  (set-car! (cdr cv)
	    (cons val (condition-variable-gates cv))))
(define (condition-variable-wait! cv)
  (let ((mutex (condition-variable-mutex cv))
	(gates (condition-variable-gates cv))
	(new-gate (make-gate)))
    (mutex-lock! mutex)
      (condition-variable-put-gates! cv new-gate)
    (mutex-unlock-primitive! mutex)
    (gate-wait! new-gate)))
(define (condition-variable-signal! cv)
  (let ((mutex (condition-variable-mutex cv))
	(gates (condition-variable-gates cv)))
    (mutex-lock! mutex)
      (for-each (lambda (g) (gate-signal! g))
		gates)
      (condition-variable-clear-gates! cv)
    (mutex-unlock-primitive! mutex)))
condition variableは使い捨てのmutexを用いて実装している。
これで、同期に関してSRFI 18で定められた手続きが使える。
調べてみると Racket ではペアへの破壊的な代入を許さないらしい。
代わりに mcons というデータ構造が用意されていてこちらは set-mcar! や set-mcdr! といった手続きで代入ができる。
R5RS に基づいて書かれた Scheme のプログラムを動かすにはペアを扱う手続きを mcons を使うものに定義し直す必要があるが、すでにそれをするパッケージが用意されている。
> (require r5rs)
とすると、set-car! や set-cdr! が定義され、cons で作ったペアに再代入できる。
]]>