How can I define functions taking "blocks" as parameters in elisp?
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.
精彩评论