MzScheme 使用技巧

改变 MzScheme 的 REPL

这一节介绍怎样改变 MzScheme 的 REPL (Read Eval Prit Loop)。

改变命令提示符 (Read)

(current-prompt-read [proc])

可以使用 current-prompt-read 来改变读取命令的函数。这个函数 必须是一个不需要参数的函数,它负责显示提示符,读取输入,然后 把输入做成一个 syntax 对象返回给解释器。

如果不带参数就返回当前的 Read 函数。

通常读取输入可以使用 read-syntax 函数来帮助。比如,下面这个 例子,把提示符换成了 "wangyin:",而输入方式不变。

(current-prompt-read
 (lambda () 
   (display "wangyin:")
   (read-syntax (current-input-port))))

改变 Eval

(current-eval [proc])

使用 current-eval 可以把当前的解释器换成另一个函数。这个函数 接受一个 syntax 对象,返回它的值。

改变 Print

proc 接受一个对象,然后显示它。

(current-print [proc])

改变 MzScheme 的处理函数

改变退出函数

可以在这里加入解释器退出时的善后处理。比如:

(define e1 (exit-handler))
(exit-handler (lambda (x) (display "exit")(newline) (e1 #t)))

线程和进程

线程的使用

(thread thunk)

thunk 是一个不需要参数的函数,返回一个线程对象。

(thread (lambda () (sleep 2) (display 7) (newline))) ; => athread descriptor 
(thread-suspend thread)
(thread-resume thread)
(kill-thread thread)

使用

(thread/suspend-to-kill thunk)

生成的线程是 kill 不死的。如果它被 kill,就会 suspend.

(thread-wait thread) ; 等待一个线程终止
(thread-dead-waitable thread) ; 制造一个 waitable,当线程完成时才 unblock
(thread-resume-waitable thread) ; 制造一个 waitable,当线程恢复运行时才 unblock
(thread-suspend-waitable thread) ; 制造一个 waitable,当线程被停止时才 unblock

sleep 函数使线程至少睡眠 x 秒。如果不提供 x,缺省为 0,也就 是把处理器让给其它线程。

(sleep [x])
(make-semaphore [init-k])
(semaphore? v)
(semaphore-post sema) ;增加信号量
(semaphore-wait sema) ;阻塞直到信号量不为0,然后减少信号量,返回 void.
(semaphore-try-wait? sema) ;就像 semaphore-wait,只是从来不阻塞。
(make-semaphore-peek sema) ;返回一个 waitable, 当 sema unblock 时就 unblock.

通道是连接线程的管道。一些线程可以往通道写东西,另一些线程把 通道里的东西读出来。如果读不到东西,线程就会阻塞。或者使用了 channel-try-get 就不会阻塞而返回 #f.

(make-channel)
(channel? v)
(channel-get channel)
(channel-try-get channel)
(channel-put channel v)
(make-channel-put-waitable channel v)

使用 object-wait-multiple 可以同时等待多个同步对象。这有点像 C 函数 select。它的语法是:

(object-wait-multiple timeout waitable ...)

可以设置一个时间 timeout 作为超时时间。如果在 timeout 之内有 某个对象得到了输入,那么返回这个输入。如果没有对象能得到输入 那么返回 #f。

timeout 如果是 0, 那就马上返回,这相当于轮询。timeout 如果 是 #f 就永远不超时。

举一个例子:

(define th1 
  (thread 
   (lambda () 
     (let ((ch (object-wait-multiple 5 ch1)))
       (if ch
           (begin
             (display ch)
             (newline))
           (display "No input\n"))))))

(channel-put ch1 "haha")

如果在第一个 sexp 执行之后 5 秒之内执行第了第二个。那么线程 th1 就会显示 "haha",否则显示 "No input"。

(current-thread)
(thread-running? thread)
(thread-dead? thread)
(thread? v)
(break-thread thread)

调试程序

可以使用 errortrace:

(require (lib "errortrace.ss" "errortrace"))

有这些函数可用:

(instrumenting-enabled)
(profiling-enabled)
(profiling-enabled #t)
(profiling-record-enabled)
(profile-paths-enabled #t)
(get-profile-results)
(output-profile-results #f #t)
(execute-counts-enabled #t)
(get-execute-counts)

怎样在 MzScheme 里使用 SRFI?

http://sourceforge.net/projects/schematics/ 下载 srfi. 然后使用

(require (lib "N.ss" "srfi"))

就行了。

MzScheme 里怎样使用 Tiny-CLOS?

可以使用 Swindle(http://www.barzilay.org/Swindle/).

然后在 MzScheme 里:

(require (lib "swindle.ss" "swindle"))

就可以使用 Tiny-CLOS 了。

Swindle 不止提供 CLOS。还有很多强大的功能。比如: