How can I modify function bindings in Common Lisp?

前端 未结 2 1901
时光说笑
时光说笑 2020-12-12 01:13

Here is something you can do in Scheme:

> (define (sum lst acc)
    (if (null? lst)
        acc
        (sum (cdr lst) (+ acc (car lst)))))
> (define s         


        
相关标签:
2条回答
  • 2020-12-12 01:57

    Because Common Lisp has a different namespace for functions, you need to use symbol-function or fdefinition.

    CL-USER> (defun foo (a)
               (+ 2 a))
    FOO
    CL-USER> (defun debug-foo (a)
               (format t " DEBUGGING FOO: ~a" a)
               (+ 2 a))
    DEBUG-FOO
    CL-USER> (defun debug-foo-again (a)
               (format t " DEBUGGING ANOTHER FOO: ~a" a)
               (+ 2 a))
    DEBUG-FOO-AGAIN
    CL-USER> (foo 4)
    6
    CL-USER> (setf (symbol-function 'foo) #'debug-foo)
    #<FUNCTION DEBUG-FOO>
    CL-USER> (foo 4)
     DEBUGGING FOO: 4
    6
    CL-USER> (setf (fdefinition 'foo) #'debug-foo-again)
    #<FUNCTION DEBUG-FOO-AGAIN>
    CL-USER> (foo 4)
     DEBUGGING ANOTHER FOO: 4
    6
    CL-USER>
    
    0 讨论(0)
  • 2020-12-12 01:58

    A typical use case for redefining functions in such a way is during debugging. Your example indicates that. Common Lisp already provides higher-level machinery for that: TRACE. Under the hood it sets the function value of the symbol, but it provides a more convenient user interface. Often something like TRACE will have many, non-standard, options.

    Tracing functions

    The following example uses Clozure Common Lisp, which is always compiling code:

    ? (defun sum (list accumulator)
        (declare (optimize debug))   ; note the debug declaration
        (if (endp list)
            accumulator
            (sum (rest list) (+ accumulator (first list)))))
    SUM
    ? (sum '(1 2 3 4) 0)
    10
    ? (trace sum)
    NIL
    ? (sum '(1 2 3 4) 0)
    0> Calling (SUM (1 2 3 4) 0) 
     1> Calling (SUM (2 3 4) 1) 
      2> Calling (SUM (3 4) 3) 
       3> Calling (SUM (4) 6) 
        4> Calling (SUM NIL 10) 
        <4 SUM returned 10
       <3 SUM returned 10
      <2 SUM returned 10
     <1 SUM returned 10
    <0 SUM returned 10
    10
    

    Then to untrace:

    ? (untrace sum)
    

    Advising functions

    In your example you have printed the arguments on entering the function. In many Common Lisp implementations there is another mechanism to augment functions with added functionality: advising. Again using Clozure Common Lisp and its advise macro:

    ? (advise sum                                 ; the name of the function
              (format t "~%Arglist: ~a" arglist)  ; the code
              :when :before)                      ; where to add the code
    #<Compiled-function (CCL::ADVISED 'SUM) (Non-Global)  #x302000D7AC6F>
    
    ? (sum '(1 2 3 4) 0)
    
    Arglist: ((1 2 3 4) 0)
    Arglist: ((2 3 4) 1)
    Arglist: ((3 4) 3)
    Arglist: ((4) 6)
    Arglist: (NIL 10)
    10
    
    0 讨论(0)
提交回复
热议问题