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

时间:2011-08-30 20:16:00

标签: ruby elisp

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

2.times do
  # whatever code is between do and end, will be executed 2 times
end

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

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

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

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

1 个答案:

答案 0 :(得分:5)

  

我如何在elisp中编写这样的函数/方法,以便在我使用时   他们,我只需要关心任务的“相关”部分,   而不是一直经历所有的样板?

您可以使用宏。

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

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

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

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

您可以对文件处理执行相同的操作。请查看with-temp-file以获取emacs 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

变为:

(with-open-file (file "some_file")
  # do something ...
  )

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

(defun times (n function)
  (do-times n (funcall function)))

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