我如何制作这款球拍代码DRYer?

Jon*_*han 7 scheme racket

我正在将一个Python脚本移植到Racket作为学习经验,我有这个功能:

(define (check-status)
    (define git [find-executable-path "git"])
    (define-values (ckot out in err)
        (subprocess #f #f #f git "checkout" "-q" "master"))
    (define-values (local lout lin lerr)
        (subprocess #f #f #f git "rev-parse" "@"))
    (define-values (remote rout rin rerr)
        (subprocess #f #f #f git "rev-parse" "@{u}"))
    (define-values (merge-base mbout mbin mberr)
        (subprocess #f #f #f git "merge-base" "@" "@{u}"))
    (display-lines (port->lines mbout))
   (define ports '(ckot out in err local lout lin lerr remote rout rin rerr merge-base mbout mbin mberr))
   (map (lambda (x)
        (cond ((input-port? x) (close-input-port x))
              ((output-port? x) (close-output-port x)))) ports))
Run Code Online (Sandbox Code Playgroud)

问题是它不是很干.由于我使用的是Lisp,并且Lisp以能够做出疯狂的事情而闻名,我想知道是否有办法获取所有子进程代码并将其解压缩,以便我可以执行以下操作:

(define (check-status)
    (define commands '(
                        '("checkout" "-q" "master") 
                        '("rev-parse" "@") 
                        '("rev-parse" "@{u}") 
                        '("merge-base" "@" "@{u}"))
    (map currently-immaginary-git-command-fn commands))
Run Code Online (Sandbox Code Playgroud)

最后得到命令列表中每个命令的输出列表.我该怎么做?由于我是整个Lisp/Scheme的新手,我正在弄清楚我的语法,而且我并不完全了解可用的资源.

Ale*_*ing 7

首先,对你想要提出更清洁的解决方案有好处!你是对的,有一种更优雅的方式去做你曾尝试过的事情.

首先,使用subprocess几乎肯定是你的特定用例过度杀伤.该racket/system模块提供了一个更简单的界面,足以满足您的需求.具体来说,我使用system*函数,它使用提供的参数执行单个进程,然后将其输出打印到stdout.

使用时system*,可以创建一个非常通用的辅助函数,该函数可以执行特定可执行文件的命令并将其输出作为字符串返回.

(define (execute-command proc-name)
  (define proc (find-executable-path proc-name))
  (? (args)
    (with-output-to-string
     (thunk (apply system* proc args)))))
Run Code Online (Sandbox Code Playgroud)

该函数本身在调用时返回一个函数.这意味着使用它来调用Git命令将如下所示:

((execute-command "git") '("checkout" "-q" "master"))
Run Code Online (Sandbox Code Playgroud)

其原因很快就会显现出来.

实际上看一下实现execute-command,我们with-output-to-string用来将system*调用的所有输出重定向到一个字符串(而不是只将它打印到stdout).这实际上只是用于parameterize设置current-output-port参数的缩写,但它更简单.

有了这个功能,我们可以check-status很容易地实现.

(define (check-status)
  (define commands
    '(("checkout" "-q" "master") 
      ("rev-parse" "@") 
      ("rev-parse" "@{u}") 
      ("merge-base" "@" "@{u}")))
  (map (execute-command "git") commands))
Run Code Online (Sandbox Code Playgroud)

现在(execute-command "git")返回一个新函数的原因变得明显:我们可以使用它来创建一个函数,然后映射commands列表以生成一个新的字符串列表.

另请注意,commands列表的定义仅'在开头使用单个.您提供的定义不起作用,事实上,ports您在原始实现中定义的列表并不是您所期望的.这是因为'(...)完全一样的(list ...)-他们是不同的,所以在使用它们时要小心.