我将如何使这个 Racket 代码更干燥?
How would I make this Racket code DRYer?
我正在将 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))
问题是它不是很干。由于我使用的是 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))
并以命令列表中每个命令的输出列表结束。我该怎么做?由于我是整个 Lisp/Scheme 的新手,所以我边走边弄清楚语法,但我并不完全了解我可用的资源。
首先,希望提出一个更清洁的解决方案对您有好处!你是对的,有一种更优雅的方式来完成你所尝试的事情。
首先,在您的特定用例中使用 subprocess
几乎肯定是矫枉过正。 racket/system
module provides a simpler interface that should be sufficient for your needs. Specifically, I'd use the system*
函数,它使用提供的参数执行单个进程,然后将其输出打印到标准输出。
使用 system*
,可以创建一个非常通用的辅助函数,该函数可以为特定的可执行文件执行命令并 return 将其输出为字符串。
(define (execute-command proc-name)
(define proc (find-executable-path proc-name))
(λ (args)
(with-output-to-string
(thunk (apply system* proc args)))))
此函数本身 return在调用时是一个 新 函数。这意味着使用它来调用 Git 命令将如下所示:
((execute-command "git") '("checkout" "-q" "master"))
其原因很快就会明了。
实际上查看 execute-command
的实现,我们使用 with-output-to-string
将 system*
调用的所有输出重定向到一个字符串中(而不是仅仅将其打印到标准输出) .这实际上只是使用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))
现在 (execute-command "git")
return 一个新函数的原因变得很明显了:我们可以用它来创建一个函数,然后映射到 commands
列表以产生一个新的字符串列表。
此外,请注意 commands
列表的定义仅在开头使用单个 '
。您提供的定义不起作用,事实上,您在原始实现中定义的 ports
列表不是您所期望的。这是因为 '(...)
与 (list ...)
不是 完全一样——它们是不同的,所以使用时要小心。
我正在将 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))
问题是它不是很干。由于我使用的是 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))
并以命令列表中每个命令的输出列表结束。我该怎么做?由于我是整个 Lisp/Scheme 的新手,所以我边走边弄清楚语法,但我并不完全了解我可用的资源。
首先,希望提出一个更清洁的解决方案对您有好处!你是对的,有一种更优雅的方式来完成你所尝试的事情。
首先,在您的特定用例中使用 subprocess
几乎肯定是矫枉过正。 racket/system
module provides a simpler interface that should be sufficient for your needs. Specifically, I'd use the system*
函数,它使用提供的参数执行单个进程,然后将其输出打印到标准输出。
使用 system*
,可以创建一个非常通用的辅助函数,该函数可以为特定的可执行文件执行命令并 return 将其输出为字符串。
(define (execute-command proc-name)
(define proc (find-executable-path proc-name))
(λ (args)
(with-output-to-string
(thunk (apply system* proc args)))))
此函数本身 return在调用时是一个 新 函数。这意味着使用它来调用 Git 命令将如下所示:
((execute-command "git") '("checkout" "-q" "master"))
其原因很快就会明了。
实际上查看 execute-command
的实现,我们使用 with-output-to-string
将 system*
调用的所有输出重定向到一个字符串中(而不是仅仅将其打印到标准输出) .这实际上只是使用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))
现在 (execute-command "git")
return 一个新函数的原因变得很明显了:我们可以用它来创建一个函数,然后映射到 commands
列表以产生一个新的字符串列表。
此外,请注意 commands
列表的定义仅在开头使用单个 '
。您提供的定义不起作用,事实上,您在原始实现中定义的 ports
列表不是您所期望的。这是因为 '(...)
与 (list ...)
不是 完全一样——它们是不同的,所以使用时要小心。