如何在elisp中定义以"块"作为参数的函数?

Geo*_*Geo 3 ruby elisp

在Ruby中,一个方法可以使用块/ lambda,并使您能够编写看起来像是语言一部分的构造.例如,类times上的方法Fixnum:

2.times do
  # whatever code is between do and end, will be executed 2 times
end
Run Code Online (Sandbox Code Playgroud)

或者例如,类中的open方法File:

File.open(some_file) do |file|
   # do something with the file; once the block finishes execution, the handle is automatically closed
end
Run Code Online (Sandbox Code Playgroud)

open方法可以有类似的实现(借用Ruby"伪代码"):

class File
  def open(file,mode="r",&blk)
    begin
      handle = probably_sys_open(file)
      if block_given?
         blk.call(handle) 
         close(handle)
      else
         return handle
      end
    rescue SomeException => e
      # whatever error handling goes on here
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

我怎样才能在elisp中编写这样的函数/方法,这样当我使用它们时,我只需要关心任务的"相关"部分,而不是一直遍历所有的样板?

dan*_*lei 5

我怎样才能在elisp中编写这样的函数/方法,这样当我使用它们时,我只需要关心任务的"相关"部分,而不是一直遍历所有的样板?

您可以使用宏.

例如,如果没有dotimes,您可以轻松地自己编写类似的内容:

(defmacro do-times (n &rest body)
  (let ((i (gensym)))
    `(do ((,i 0 (1+ ,i)))
         ((= ,i ,n))
       ,@body)))
Run Code Online (Sandbox Code Playgroud)

现在,(do-times 3 (princ 'x))将做你期望的事情(你可能需要先做(require 'cl)).

这可以通过编写为您编写样板文件的代码来实现.我不会在这里给你一个完整的宏教程 - 快速谷歌搜索将为你提供足够的教程和其他信息来开始.

您可以对文件处理执行相同的操作.看一下with-temp-fileemacs lisp示例.例如,在CL中with-open-file,它与第二个Ruby片段具有几乎相同的功能.所以:

File.open(some_file) do |file|
   # do something with the file; once the block finishes execution, the handle is automatically closed
end
Run Code Online (Sandbox Code Playgroud)

变为:

(with-open-file (file "some_file")
  # do something ...
  )
Run Code Online (Sandbox Code Playgroud)

除了你可以用宏做的语法抽象,你还可以编写更高阶的函数:

(defun times (n function)
  (do-times n (funcall function)))
Run Code Online (Sandbox Code Playgroud)

现在,此函数将采用计数和另一个将执行的函数n.(times 3 (lambda () (princ 'x)))会做你所期望的.或多或少,Ruby块只是这类事物的语法糖.