开发者

How can I define functions taking "blocks" as parameters in elisp?

开发者 https://www.devze.com 2023-03-31 16:30 出处:网络
In Ruby, a method can take blocks/lambdas and enable you to write constructs that kind of look like they\'re part of the language. For example, the times method on the Fixnum class:

In Ruby, a method can take blocks/lambdas and enable you to write constructs that kind of look like they're part of the language. For example, the times method on the Fixnum class:

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

Or for example, the open method in the File class:

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

The open method could have an implementation similar to this ( excuse the Ruby "pseudocode" ):

class File
  def open(file,mode="r",&blk)
    begin
      开发者_如何学Pythonhandle = 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

How could I write such functions/methods in elisp, so that when I use them, I would only need to care about the "relevant" parts of a tasks, instead of going through all the boilerplate all the time?


How could I write such functions/methods in elisp, so that when I use them, I would only need to care about the "relevant" parts of a tasks, instead of going through all the boilerplate all the time?

You could use macros for that.

If, for example, there were no dotimes, you could easily write something similar yourself:

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

Now, (do-times 3 (princ 'x)) will do what you'd expect (You might need to (require 'cl) first).

This works by writing code that writes the boilerplate for you. I won't give you a full macro tutorial here -- A quick google search will provide you with enough tutorials and other information to get started.

You can do the same thing for file handling. Take a look at with-temp-file for an emacs lisp example. In CL, for example, there is with-open-file, which has pretty much the same functionality as your second Ruby snippet. So:

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

becomes:

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

Besides the syntactic abstractions you can do with macros, you could also write higher order functions:

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

Now, this function will take the count and another function, which will be executed n times. (times 3 (lambda () (princ 'x))) will do what you'd expect. More or less, Ruby blocks are just syntactic sugar for this kind of thing.

0

精彩评论

暂无评论...
验证码 换一张
取 消