1

是否可以在csi解释程序代码时更新程序代码,鸡方案解释器?如果是这样,怎么做?

这样我就可以交互式地更改部分代码并立即看到更改的效果。例如,假设我编写了以下程序:

(define (loop)
   (print "Ciao")
   (rest 1)
   (loop))

(loop)

(假设(rest 1)具有暂停程序一秒钟的效果)。

如果我通过csi运行这个程序,它会每秒打印一次字符串“Ciao”​​。如果我将字符串“Ciao”​​更改为其他内容,例如“else”,并保存程序代码文件,然后csi继续解释旧程序代码,因此我不断看到字符串“Ciao”​​。在这种情况下,我希望当我用“else”替换字符串“Ciao”​​保存修改后的代码时,csi通过查看修改后的文件而不是旧文件来继续其解释工作。这样我就获得了一些“Ciao”​​作为输出,然后是一些“else”:当我在源代码中将“Ciao”​​替换为“else”时,“else”开始出现。

4

2 回答 2

2

一般来说,答案是“不要”。您应该使用 REPL 的方式是评估对它的零碎更改,然后评估一两个函数以确保一切按预期进行。这种方法的一部分是构建您的程序,以便可以轻松地对其进行分段测试,这意味着不会自动启动任何无限循环。在您询问的特定情况下,您可以改为写

(define (do-stuff)
   (print "Ciao"))

(define (main-loop)
   (do-stuff)
   (rest 1)
   (main-loop))

(define (start) (main-loop))

您现在可以逐步开发do-stuff,定期评估您的解释器的新版本并调用它们以确保它们工作,然后start在您确信它正在做正确的事情时最终调用。

你可能会从这个关于 Common Lisp的类似问题中得到启发。

顺便说一句,如果您使用的是 Common Lisp 和 SLIME,您现在可以或多或少地按照您的建议进行操作:

(defun do-stuff ()
  (format t "Ciao~%"))

(defun main-loop ()
  (loop (progn (do-stuff)
               (sleep 1))))

(main-loop)

启动它会开始Ciao在你的 SLIME REPL 中的不同行上打印。如果你do-stuff改为

(defun do-stuff ()
  (format t "else~%"))

然后用C-c C-c(默认绑定slime-compile-defun)点击它,你会看到你的 SLIME REPL 开始打印else飞行中的行。

CL-USER> (main-loop)
Ciao
Ciao
Ciao
; compiling (DEFUN DO-STUFF ...)else
else
else
else
else
else
; Evaluation aborted on NIL. User break.
CL-USER> 

我不确定如何在 Scheme 中完成同样的事情,但我有理由相信这是可能的。

话虽如此,您有时想要运行一个程序,其中一部分是无限的loop。一个真实的例子是在测试某种 TCP 服务器时。如果您处于这种情况,并且您想要的工作流程是

  1. 写文件
  2. csi my-file.scm
  3. 编辑文件
  4. csi
  5. csi my-file.scm
  6. goto 3

而且您基本上只想自动化步骤 4 到 6,您需要一个外部工具来为您完成。看一下entror hsandbox(后者没有开箱即用的 Scheme 支持,但看起来并不难添加)。

于 2015-02-23T16:25:27.927 回答
2

没有通用的方法可以让正在运行的程序检查其更改源,但您似乎在 Chicken 中有足够的可用功能来滚动您自己的:

(use posix)
(use srfi-18)

(define (watch-reload! file)
  (define (tsleep n)
    (thread-sleep! (seconds->time (+ n (time->seconds (current-time))))))
  (define (get-time)
    (file-modification-time file))
  (thread-start! 
   (lambda ()
     (let loop ((filetime '())) 
       (let ((newtime  (get-time)))
         (when (not (equal? filetime newtime))
           (load file))
         (tsleep 10)
         (loop newtime))))))

现在您所要做的就是使用watch-reload!而不是,load如果文件已被修改,它将每 10 秒检查一次并重新加载。如果您在文件无效时保存方案,它将停止工作,直到您watch-reload!再次调用它。

可能鸡程序员可能有更好的解决方案。

于 2015-02-23T19:06:46.153 回答