在Chicken Scheme中运行时更改程序代码

时间:2015-02-23 00:04:02

标签: scheme interpreter chicken-scheme

是否可以在 csi (鸡计划解释器)解释程序代码时更新程序代码?如果是这样,怎么样?

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

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

(loop)

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

如果我运行这个程序,通过 csi ,它会打印字符串" Ciao"每一秒。如果我改变字符串" Ciao"进入别的东西,例如进入" else",然后我保存程序代码文件,然后 csi 继续解释旧的程序代码,所以我不断看到字符串"侨&#34 ;.在这种情况下,我希望当我用字符串" Ciao"保存修改后的代码时替换为"否则", csi 通过查看修改后的文件而不是旧文件来继续其解释作业。 所以我获得了一些" Ciao"其次是一些"否则":"否则"当我取代" Ciao"时开始出现by" else"在源代码中。

2 个答案:

答案 0 :(得分:2)

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

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

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

(define (start) (main-loop))

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

你可以从this similar question获得关于Common Lisp的里程数。

顺便说一句,如果您使用的是Common Lisp和SLIME,那么您现在可以做更多或更少的建议:

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

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

(main-loop)

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

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

然后使用C-c C-cslime-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
  7. 并且您基本上只想自动执行第4步到第6步,您需要一个外部工具来为您完成。看看entrhsandbox(后者没有开箱即用的方案支持,但它看起来似乎不太难添加)。< / p>

答案 1 :(得分:2)

没有一种常用的方法可以让正在运行的程序检查其变化来源,但是您似乎已经有足够多的可用于自己的游戏:

(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!为止。

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