首页 > Elisp, 中级, > Emacs中诡异的宏

Emacs中诡异的宏

2009年11月6日 ahei 发表评论 阅读评论

今天在写一个宏时, 碰到了一个很诡异的问题. 问题是这样的:

1
2
(setq list '("C-x e" "C-x f"))
(kbd (nth 0 list))

emacs却报错:

Debugger entered--Lisp error: (wrong-type-argument integer-or-marker-p (nth 0 list))

这么简单的一个程序, 却运行错误, 把我搞的莫名其妙, 弄了好久都不知道为啥会出错, 最后请教一位emacs前辈, 才搞明白了. 原因是: kbd是一个宏. 那为什么它是一个宏, 就会报那个错呢? 想要搞清楚这个原因的话, 我们先必须搞清楚emacs中宏与函数的异同点以及emacs中的宏与c中的宏的异同点。

Elisp中函数与宏的比较

  • 相同点
    函数调用的时候要对函数体进行求值,宏调用的时候要对宏体进行调用,比如:

    1
    2
    3
    4
    5
    
    (defun test-fun (a b)
      (+ a b))
     
    (defmacro test-macro (a b)
      (+ a b))

    (test-fun 1 2) => 3
    (test-macro 1 2) => 3
    这点上它们是相同的

  • 不同点
    1. 函数是对参数进行求值以后才传到函数体里面去的,而宏不求值直接作为一个symbol传到宏体里面去的,这点很重要,如果没有理解好这点,会犯好多错误,我们来看看下面的例子:
      1
      2
      3
      
      (test-fun 1 (+ 2 3)) => 6
      (test-macro 1 (+ 2 3))
      emacs报错: Debugger entered--Lisp error: (wrong-type-argument number-or-marker-p (+ 2 3))

      为什么调用(test-macro 1 (+ 2 3))的时候emacs会报错呢, 原因就是因为对宏求值的时候, 直接把参数做为宏的参数, 并不求值, 我们来看一下emacs报的堆栈提示就知道了:

      1
      2
      3
      4
      5
      6
      7
      8
      
      Debugger entered--Lisp error: (wrong-type-argument number-or-marker-p (+ 2 3))
        +(1 (+ 2 3))
        (lambda (a b) (+ a b))(1 (+ 2 3))
        (test-macro 1 (+ 2 3))
        eval((test-macro 1 (+ 2 3)))
        eval-last-sexp-1(nil)
        eval-last-sexp(nil)
        call-interactively(eval-last-sexp nil nil)

      从上面, 很明显就可以看出没有先对(+ 2 3)求值, 就直接作为参数传给宏了.

    2. 函数对函数体求值后, 就完事了, 宏不同, 它对宏体求值后, 还要对求值后的表达式再求值一遍, 我们来看下面的例子:
      1
      2
      3
      4
      5
      
      (defun test-fun (a b)
        (list '+ a b))
       
      (defmacro test-macro (a b)
        (list '+ a b))

      (test-fun 1 2) => (+ 1 2)
      (test-macro 1 2) => 3
      为什么它们的结果不同? 原因就是elisp对宏体求值后, 对求值后的结果再求值一遍, 即: 对宏体求值得到(+ 1 2), 这个和(test-fun 1 2)结果是一样的, 但是此时elisp解释器并没有止步, 还要进一步对(+ 1 2)行求值, 进而最终得到3.

Elisp中的宏与c中的宏的异同点

  • 相同点 它们都是不对参数进行求值, 就直接作为参数传给宏.
  • 不同点 c中的宏是直接进行宏替换, 然后对替换后的表达式进行求值, 而且这个是在预处理阶段进行的, 而elisp中的宏则是对宏体进行求值后, 再进行宏扩展, 它则是在程序运行过程中进行的. 来看下面的例子:
    1
    2
    3
    
    #define test_macro_c(a, b) printf("%d%d", a, b)
    (defmacro test-macro-elisp (a b)
      (list '+ a b))

    test_macro_c(1, 1+2)进行宏扩展后变为printf(“%d%d”, 1, 1+2)
    test-macro-elisp(1, 2)并不是像c中那样简单的扩展变为(list ‘+ 1 2), 然后再对(list ‘+ 1 2)行求值, 最终得到结果(+ 1 2), 而是先对宏体进行求值得到(+ 1 2), 然后再进行宏展开, 即对刚才的结果进行再求值, 最终得到3.

经过上面的分析, 我相信对于文中开头提出的那个问题, 我们很容易就弄清楚原因了.
我们先来看看kbd的定义:

1
2
3
4
5
(defmacro kbd (keys)
  "Convert KEYS to the internal Emacs key representation.
KEYS should be a string constant in the format used for
saving keyboard macros (see `edmacro-mode')."
  (read-kbd-macro keys))

(kbd (nth 0 list)), 先对宏体进行求值, 即对(read-kbd-macro (nth 0 list))进行求值, 注意: 此时(nth 0 list)没有被求值, 只是作为宏参数传进来了, 它并不是read-kbd-macro所要求的参数, 所以最终出现了那个错误. 我们来看一下emacs的堆栈信息, 也能了解到这点:

1
2
3
4
5
6
7
8
Debugger entered--Lisp error: (wrong-type-argument integer-or-marker-p (nth 0 list))
  read-kbd-macro((nth 0 list))
  (lambda (keys) (read-kbd-macro keys))((nth 0 list))
  (kbd (nth 0 list))
  eval((kbd (nth 0 list)))
  eval-last-sexp-1(nil)
  eval-last-sexp(nil)
  call-interactively(eval-last-sexp nil nil)

如果想要刚才的代码能运行, 可以把kbd的定义改为:

1
2
(demacro kbd (keys)
  `(read-kbd-macro ,keys))

这样,先对宏体求值得到(read-kbd-macro “C-x e”), 然后再求值就可以了.

虽然emacs的宏很诡异, 但是能实现一些比较强大的功能, 例如:

1
2
3
4
5
6
7
8
(defmacro def-remember-command (command)
  "Make definition of command which remember `poiint'."
  `(defun ,(concat-name command "-remember") ()
     ,(concat "When `" command "' remember `point'.")
     (interactive)
     (call-interactively (intern ,command))
     (if mark-active
         (setq last-region-end (point)))))

调用(def-remember-command “next-line”), 先对宏体求值得到:

1
2
3
4
5
6
7
(defun next-line-remember nil "When `next-line' remember `point'."
  (interactive)
  (call-interactively
   (intern "next-line"))
  (if mark-active
      (setq last-region-end
            (point))))

然后再对求值后的结果再求值, 最终实现定义函数next-line-remember的功能.

分享家:Addthis中国
GD Star Rating
loading...
Emacs中诡异的宏, 8.7 out of 10 based on 7 ratings 标签:editor, Elisp, Emacs, lambda, lisp, mode, se, vi, , 扩展

相关日志

分类: Elisp, 中级,
  1. sweord
    2010年10月7日00:11 | #1

    很好的学习贴,实用 :-)

    [回复]

  2. Lowe
    2011年1月4日22:23 | #2

    没看懂关于C和elisp的宏的区别,onlisp上写先展开,执行的时候求值,这不是和c一样么?是我没看懂,还是 elisp和common lisp不一样?

    [回复]

    ahei 回复:

    @Lowe, :-) ,关键理解这个例子:

    #define test_macro_c(a, b) printf("%d%d", a, b)
    (defmacro test-macro-elisp (a b)
      (list '+ a b))

    [回复]

    Lowe 回复:

    @ahei, 就是说lisp里面的两步,展开->求值,第一步展开不是c里面的替换,而是替换之后求值? :-D

    [回复]

    ahei 回复:

    @Lowe, en

    [回复]

  3. 小和平鸽
    2011年1月5日14:48 | #3

    有好多看起来像 typo 的地方。麻烦 ahei 修改一下,方便我们准确理解。

    [回复]

    ahei 回复:

    @小和平鸽, 哪typo啦?

    [回复]

    小和平鸽 回复:

    @ahei, 我的意思是这个地方。不过又仔细看了一遍以后发现应该没有敲错。不过这个地方看起来是比较绕。能有一个更容易理解的例子就好了。

    test_macro_c(1, 1+2)进行宏扩展后变为printf(“%d%d”, 1, 1+2)
    test-macro-elisp(1, 2)并不是像c中那样简单的扩展变为(list ‘+ 1 2), 然后再对(list ‘+ 1 2)行求值, 最终得到结果(+ 1 2), 而是先对宏体进行求值得到(+ 1 2), 然后再进行宏展开, 即对刚才的结果进行再求值, 最终得到3.

    [回复]

    ahei 回复:

    @小和平鸽, 这个确实是很绕的,你可以看info里面的解释, 那里面写的也挺绕的,只能自己好好意会了

    [回复]

  4. 尘羽
    2011年3月9日17:45 | #4

    (demacro kbd (keys)
    `(read-kbd-macro ,keys))
    这样改后,怎么运行还是有错?

    [回复]

  5. 2016年4月7日04:59 | #5

    Thank You Sir! GO BEAVERS! http://www.michaelkorshandbags.us.org Pulliam Living Trust, from Crittenden County Circuit Court. v http://www.michaelkorsoutletbuy.us.com
    III-48 Select SUV Models Currently in Production in the UK III-48 B. louis vuitton handbags Toole Ave.
    LB: Cole Lobby, Clackamas, junior ray ban outlet Once upon a time, he was considered one of the top pitching prospects in the game, and it’s not hard to envision Gausman emerging as the club’s top starter if they finally leave him alone. t coach bags
    Low dose ritonavir, which is part of VIEKIRAX, may select for PI resistance in HIV co-infected patients without ongoing antiretroviral therapy. http://www.coachfactorysoutlet.com You are allowed a full market value (FMV) deduction for a donation of publicly traded securities held for more than a year.
    g Tonight’s Fantasy 5 jackpot is $212,000. The drawing is at 7:29 p.m. Deadline is 7:08 p.m. coach outlet online But he said the president’s health care law saved his life after he was diagnosed with an autoimmune disease and ran out of money for treatment. coach outlet store
    All the Stems gals were — still are — sweet,friendly, helpful. michael kors handbags But that’s something I haven’t done in my two trips here. http://www.coachhandbags.net.co
    James H. Mahoney and Joyce E. Mahoney, individually and trustees, and Mahoney Realty Trust to Joyce E. Mahoney, 409 Alvord Place, $100. coach outlet He told the committee that voters weighing in on a single issue are better informed than the broader electorate that votes in primaries and general elections. z coach outlet
    Matt Forte, CHI, at Green Bay12. michael kors handbags There is no precipitation in the forecast.
    We could also rent it out for events, put the structure on the quiet side nearer The Vault. michael kors online Instead, it will offer an aggregate assessment of casualties outside of areas of “active hostilities” a designation that takes into account the scope and intensity of fighting and is used to determine when Obama’s specific counterterrorism policies apply.
    Why don t you like this ad ?It s offensive to meI keep seeing thisIt s not relevant to meSomething elseDoneTrendingClinton hits Bernie on vote for border ‘vigilantes’Liz GoodwinTrendingCharlie Hunnam Asks Fans to Stop Attacking His Girlfriend: She Is an Intelligent, Beautiful, Kind Person PeopleTrendingMoney wasn t only reason Brock Osweiler dissed John Elway and BroncosYahoo Sports17 Most Hilarious Fails of 2015Thank you for your feedbackWe ll review and make changes needed. coach outlet online It came down the aerial ladder truck from the Tenth street side of the hotel.
    ” Stairs unfolded in the back and people poured out. coach outlet store For more than 50 years, NSU has been awarding degrees in a wide range of fields, while fostering groundbreaking research and an impactful commitment to community.
    n We’ve gathered six soup recipes from the PennLive files for everything from a chicken dill orzo to a sausage minestrone coach outlet store online If he leads Denver to a victory against Carolina on Sunday, Manning’s ability to set aside the glow of winning the title, and to listen to candid advice, will set the framework for his decision.
    Partygoers can catch the score on one of several big screens, or challenge each other to games like corn hole and ping-pong. coach outlet store online Time is your best friend when it comes to compound interest. f coach outlet store online
    and in Pennsylvania, according to Lou D’Amico, president and executive director of the Pennsylvania Independent Oil and Gas Association coach bags I called my best friend for some of that old-time enlightenment.
    s Mark Buehrle has mileage on his arm, too. But Buehrle hasn’t broken down despite throwing 200-plus innings every season from 2001-14. He just missed the mark in 2015 with 198 2/3 innings pitched. http://www.michaelkorshandbagsrack.us.com I don’t criticize his interests. j
    residents michael kors outlet Dobson’s Sam Gelfan had 13 kills, Kailee McCoy had 11 kills and Cassidy Roer had 10 digs to lead the Mustangs (4-7, 2-1) to a road win against St. oakley sunglasses
    Hernandez-Flores said that the Wildcats were not as sure of their own identity intheir September match, but this time they were ready. He also said that the twopoints that Woodburn scored which came off of penalty kicks were kind oflucky. http://www.coachoutlet.cc Rock Gardening Primer, 10 a. z ray ban sunglasses
    Also, a seven-year historic analysis is provided for these markets. coach outlet online People are noticing.
    Mike Thelin, the Feast Portland co-founder who is curating the market’s food tenants, says the new Salt Straw will be “unlike any other ice cream experience in Portland.” http://www.cheapchinajerseysnfl.us.org “We are executing a focused strategy to stabilize and grow operating cash flow,” Thomas said in the statement. n michael kors outlet online
    The 11th annual Tour de Tanks will take place ovr three March weekends, beginning March 5-6. coach outlet store online The mitigation measures will reduce impacts from tower and temporary road construction, among other things, he said.

    [回复]

  6. 2017年8月21日20:29 | #6

    Good answers in return of this query with solid arguments and describing all about
    that.

    [回复]

  1. 本文目前尚无任何 trackbacks 和 pingbacks.
:wink: :-| :-x :twisted: :) 8-O :( :roll: :-P :oops: :-o :mrgreen: :lol: :idea: :-D :evil: :cry: 8) :arrow: :-? :?: :!: