I am using SBCL, Emacs, and Slime. Hence, I can do:
CL-USER> (defvar example #'(lambda (x) (* x 20)))
EXAMPLE
CL-USER> (funcall example 10)
200
Ok. It works as expected. Using the library Dexador, I can also so:
CL-USER> (ql:quickload :dexador)
To load "dexador":
Load 1 ASDF system:
dexador
; Loading "dexador"
.......
(:DEXADOR)
CL-USER> (dex:get "http://www.paulgraham.com")
"big HTML ommited"
200
#<HASH-TABLE :TEST EQUAL :COUNT 11 {10029F1443}>
#<QURI.URI.HTTP:URI-HTTP http://www.paulgraham.com>
#<SB-SYS:FD-STREAM for "socket 10.0.0.193:44936, peer: 74.6.52.135:80" {1002681F73}>
Now, I am trying to make the argument to be passed be a function! More specifically, the dex:get
function. I tried different approaches, but none of them worked out:
CL-USER> (defvar example-failing #'(lambda (x) (x "http://www.paulgraham.com")))
; in: DEFVAR EXAMPLE-FAILING
; (LAMBDA (X) (X "http://www.paulgraham.com"))
;
; caught STYLE-WARNING:
; The variable X is defined but never used.
; in: DEFVAR EXAMPLE-FAILING
; (X "http://www.paulgraham.com")
;
; caught STYLE-WARNING:
; undefined function: COMMON-LISP-USER::X
;
; compilation unit finished
; Undefined function:
; X
; caught 2 STYLE-WARNING conditions
EXAMPLE-FAILING
CL-USER> (funcall example-failing dex:get)
; Evaluation aborted on #<UNBOUND-VARIABLE GET {1002C57103}>.
CL-USER> (funcall example-failing 'dex:get)
; Evaluation aborted on #<UNDEFINED-FUNCTION X {1002DEA263}>.
CL-USER> (funcall example-failing #'dex:get)
; Evaluation aborted on #<UNDEFINED-FUNCTION X {1002F906C3}>.
CL-USER> (funcall example-failing (function dex:get))
; Evaluation aborted on #<UNDEFINED-FUNCTION X {1003147F83}>.
I managed to do it with:
CL-USER> (defvar hacky-eval #'(lambda (x) (eval x)))
HACKY-EVAL
CL-USER> (funcall hacky-eval (dex:get "http://www.paulgraham.com"))
"big html omitted"
But, this feels as bad practice. Is there another way to fix this?
Thanks
Your code:
(defvar example-failing
#'(lambda (x)
(x "http://www.paulgraham.com")))
This makes no sense in Common Lisp. x
is a variable. You can't use a variable as a function as in (x arg)
. In Common Lisp there are different namespaces for functions and variables. For example LET
introduces a local variable and FLET
introduces a local function.
The ways to call a function bound to a variable are:
(funcall x arg)
(apply x (list arg))
Thus correct examples would be:
(defvar example-failing
#'(lambda (x)
(apply x (list "http://www.paulgraham.com"))))
or
(defvar example-failing
#'(lambda (x)
(funcall x "http://www.paulgraham.com")))
Your solution is no solution
This is your example:
CL-USER> (defvar hacky-eval #'(lambda (x) (eval x)))
HACKY-EVAL
CL-USER> (funcall hacky-eval (dex:get "http://www.paulgraham.com"))
"big html omitted"
This does not work as you think.
(funcall hacky-eval (dex:get "http://www.paulgraham.com"))
is just the same as
(funcall hacky-eval "big html omitted")
and then
(eval "big html omitted")
and then
"big html omitted"
All your call to eval
does is to evaluate a string to itself.
You really need to understand basic evaluation rules in Lisp:
(defun foo (arg)
(eval arg))
(foo (+ 3 4))
is simply the same as:
(defun foo (arg)
arg)
(foo (+ 3 4))
which is the same as
(identity (+ 3 4))
Note: if you pass just self evaluating data to EVAL, then all it does is to return the data
A function call (foo (+ 1 2))
works like this: