Search code examples
common-lisp

Understanding sharp quote in common lisp


In my experiments below I've abbreviated where the REPL returns an error, & added [num] so these can be referenced in discussion.

I'm a bit confused as to why my attempts to call a function stored in a variable are failing. It seems to me that the syntax is more complex than it needs to be.

Why can I issue neither (f 3) nor even (#'f 3)? Is sharp quote not allowed as the first element of a form? Why is funcall required here?

[235]> (setf f #'abs)               ; I'm ok with this
#<SYSTEM-FUNCTION ABS>

[236]> (abs 3)                      ; This is fine
3

[237]> (f 3)                        ; Err due to sep. fn namespace. OK.
-- Err[1]: "Undefined function f" --

[238]> (#'f 3)                      ; Don't get what this err is telling me...
-- Err[2]: "#'F is not a function name, try using a symbol instead"

[239]> (funcall #'f 3)              ; seems very long winded...!
3

Does this mean system functions are treated differently from user defined functions?

For completeness:

[240]> (funcall abs 3)
-- Err[3]: variable ABS has no value -- ; I get why this is an error.

[241]> (funcall #'abs 3)                ; Isn't this verbose... ?
3

I haven't got to the symbols chapter in ANSI Common Lisp yet, maybe that will help... thanks for any tips.


Solution

  • Function names have their own namespace

    We can set the function in the function namespace:

    CL-USER 1 > (setf (fdefinition 'f) #'abs)
    #<Function ABS 80E033E309>
    
    CL-USER 2 > (f -42)
    42
    

    FDEFINITION gets the function object from a symbol naming a function. One can also use SETF to set the function.

    More examples

    [235]> (setf f #'abs)               ; I'm ok with this
    #<SYSTEM-FUNCTION ABS>
    

    Above kind of sets a variable named f to a function object - from the function called abs.

    [236]> (abs 3)                      ; This is fine
    3
    

    Above called the function abs.

    [237]> (f 3)                        ; Err due to sep. fn namespace. OK.
    

    Above: there is no function named f.

    -- Err[1]: "Undefined function f" --
    
    [238]> (#'f 3)                      ; Don't get what this err is telling me...
    -- Err[2]: "#'F is not a function name, try using a symbol instead"
    

    Above: Common Lisp accepts only symbols as function names, symbols as macro names, symbols as special operators or lambda expressions as the first element of a cons form. (function f) is not a function name.

    Does this mean system functions are treated differently from user defined functions?

    No.

    [239]> (funcall #'f 3)              ; seems very long winded...!
    3
    

    Above calls the function funcall with the function object from the named function f. funcall then calls this function object with 3 as the argument.

    seems very long winded

    It is.

    Why can I issue neither (f 3) nor even (#'f 3)? Is sharp quote not allowed as the first element of a form?

    Because f is not naming a function. It names a variable. #'f is also not a function name. We are required to use a function name (a symbol actually).

    Namespaces

    Common Lisp (like some other Lisp dialects) has two namespaces for functions and for variables.

    Defining a variable foo:

    CL-USER 54 > (defvar foo 3)
    FOO
    

    Defining a function foo:

    CL-USER 55 > (defun foo (x) (* foo 10))
    FOO
    

    We can call the function foo with the value obtained from the variable foo:

    CL-USER 56 > (foo foo)
    30
    

    How to get the function object from the global name of the function:

    CL-USER 57 > (fdefinition 'foo)
    #<interpreted function FOO 4060001CAC>
    
    CL-USER 58 > (symbol-function 'foo)
    #<interpreted function FOO 4060001CAC>
    

    Same as above, but with a short notation:

    CL-USER 58a > #'foo
    #<interpreted function FOO 4060001CAC>
    
    CL-USER 59 > (function foo)            ; works also for local functions
    #<interpreted function FOO 4230008AAC>
    

    How to get a value from a global variable:

    CL-USER 60 > (symbol-value 'foo)
    3
    

    Or just use the variable:

    CL-USER 61 > foo
    3
    

    Some positives:

    Positive: No name clashes.

    We can write

    (defun foo (list) (list list))
    

    and don't have to write

    (defun foo (lst) (list lst))
    

    Positive: simpler compilation

    (let ((list 3))
      (list 1 list 3))
    

    Above will never be an error in Common Lisp. In Scheme it would be an error: 3 is not a function.