Hi,
I'm still trying to grapple with the lisp's "functions as data" concept.
I've been reading some blogs and I found this one:
http://www.lurklurk.org/cpp_clos.html
I think it's a very good article. Unfortunately, I'm having problems
with some lisp code under the "function objects" item.
The author is trying to show how you can return a raw list that later
may be interpreted as a function call. Here's the relevant code:
(defun f (op i)
(funcall op i))
(defun addn (n)
(list 'lambda '(x) (list '+ 'n n)))
;;This is supposed to evaluate to 10
(f (addn 3) 7)
Now, the problem is that neither SBCL no CLISP would accept this.
Maybe there's just a syntax error. But I couldn't fix it.
But even if the syntax error could be fixed, here's what
I'm really baffled at: the return from (addn 3) will return an S
expression (lambda (x) (+ n 3)). This s-expression needs to be evaluated
before f can treat it as a function. Right? It feels like a call to
"eval" is missing somewhere. I re-wrote it like this:
(f (eval (addn 3)) 7)
And it seems to work. But now I'm afraid that I'm missing something
important. The call to eval (as I understand) will basically invoke the
interpreter (or compiler for compiled code) to interpret (or compile)
S-expression (lambda (x) (+ n 3)). But in author's original code, it
looks like that S-expression can be understood directly, without
interpreter's (or compiler's) help. If that were true, it would be truly
amazing and I'd have to change some of my world-concepts ...
So, what gives?
Thanks,
Andy.
|
|
0
|
|
|
|
Reply
|
Andy
|
10/25/2010 10:14:12 PM |
|
On Oct 25, 6:14=A0pm, Andy Venikov <swojchelo...@gmail.com> wrote:
> Hi,
>
> I'm still trying to grapple with the lisp's "functions as data" concept.
> I've been reading some blogs and I found this one:
>
> http://www.lurklurk.org/cpp_clos.html
>
> I think it's a very good article. Unfortunately, I'm having problems
> with some lisp code under the "function objects" item.
> The author is trying to show how you can return a raw list that later
> may be interpreted as a function call. Here's the relevant code:
>
> (defun f (op i)
> =A0 =A0 =A0(funcall op i))
>
> (defun addn (n)
> =A0 =A0(list 'lambda '(x) (list '+ 'n n)))
>
> ;;This is supposed to evaluate to 10
> (f (addn 3) 7)
>
> Now, the problem is that neither SBCL no CLISP would accept this.
> Maybe there's just a syntax error. But I couldn't fix it.
>
> But even if the syntax error could be fixed, here's what
> I'm really baffled at: the return from (addn 3) will return an S
> expression (lambda (x) (+ n 3)). This s-expression needs to be evaluated
> before f can treat it as a function. Right? It feels like a call to
> "eval" is missing somewhere. I re-wrote it like this:
>
> (f (eval (addn 3)) 7)
>
> And it seems to work. But now I'm afraid that I'm missing something
> important. The call to eval (as I understand) will basically invoke the
> interpreter (or compiler for compiled code) to interpret (or compile)
> S-expression (lambda (x) (+ n 3)). But in author's original code, it
> looks like that S-expression can be understood directly, without
> interpreter's (or compiler's) help. If that were true, it would be truly
> amazing and I'd have to change some of my world-concepts ...
>
> So, what gives?
>
> Thanks,
> =A0 =A0 Andy.
CL-USER> (lisp-implementation-type)
"Clozure Common Lisp"
CL-USER> (lisp-implementation-version)
"Version 1.6-dev-r14370M-trunk (LinuxX8632)"
CL-USER> (defun ff (op i)
(funcall op i))
FF
CL-USER> (defun addn (n)
(lambda (x) (+ x n)))
ADDN
CL-USER> (ff 'addn 7)
#<COMPILED-LEXICAL-CLOSURE (:INTERNAL ADDN) #x1A7E72BE>
CL-USER> (ff (addn 3) 7)
10
|
|
0
|
|
|
|
Reply
|
vanek (323)
|
10/25/2010 10:43:46 PM
|
|
On 10/25/2010 6:43 PM, vanekl wrote:
<snip>
>> (defun f (op i)
>> (funcall op i))
>>
>> (defun addn (n)
>> (list 'lambda '(x) (list '+ 'n n)))
>>
>> ;;This is supposed to evaluate to 10
>> (f (addn 3) 7)
<snip>
> CL-USER> (lisp-implementation-type)
> "Clozure Common Lisp"
> CL-USER> (lisp-implementation-version)
> "Version 1.6-dev-r14370M-trunk (LinuxX8632)"
> CL-USER> (defun ff (op i)
> (funcall op i))
> FF
> CL-USER> (defun addn (n)
> (lambda (x) (+ x n)))
> ADDN
> CL-USER> (ff 'addn 7)
> #<COMPILED-LEXICAL-CLOSURE (:INTERNAL ADDN) #x1A7E72BE>
> CL-USER> (ff (addn 3) 7)
> 10
But isn't this code different from the original?
In your case function ff returns the result of evaluating S-expression
(lambda (x) (+ x n)) which will be a function-form. In the original
version, addn was returning the S-expression unevaluated. Someone has to
evaluate it to construct a function object, right?
Thanks,
Andy.
|
|
0
|
|
|
|
Reply
|
Andy
|
10/25/2010 11:02:48 PM
|
|
On Oct 25, 7:02=A0pm, Andy Venikov <swojchelo...@gmail.com> wrote:
> On 10/25/2010 6:43 PM, vanekl wrote:
> <snip>
>
> >> (defun f (op i)
> >> =A0 =A0 =A0 (funcall op i))
>
> >> (defun addn (n)
> >> =A0 =A0 (list 'lambda '(x) (list '+ 'n n)))
>
> >> ;;This is supposed to evaluate to 10
> >> (f (addn 3) 7)
>
> <snip>
>
> > CL-USER> =A0(lisp-implementation-type)
> > "Clozure Common Lisp"
> > CL-USER> =A0(lisp-implementation-version)
> > "Version 1.6-dev-r14370M-trunk =A0(LinuxX8632)"
> > CL-USER> =A0(defun ff (op i)
> > =A0 =A0(funcall op i))
> > FF
> > CL-USER> =A0(defun addn (n)
> > =A0 =A0(lambda (x) (+ x n)))
> > ADDN
> > CL-USER> =A0(ff 'addn 7)
> > #<COMPILED-LEXICAL-CLOSURE (:INTERNAL ADDN) #x1A7E72BE>
> > CL-USER> =A0(ff (addn 3) 7)
> > 10
>
> But isn't this code different from the original?
> In your case function ff returns the result of evaluating S-expression
> (lambda (x) (+ x n)) which will be a function-form. In the original
> version, addn was returning the S-expression unevaluated. Someone has to
> evaluate it to construct a function object, right?
>
> Thanks,
> =A0 =A0 Andy.
Yes, you're right, the code is a bit different. Instead of evaluating
a function, it's trying to evaluate a CONS (list).
So, instead of creating a function, create a list:
CL-USER> (defun addn (n)
;; (lambda (x) (+ x n)))
(list 'lambda '(x) (list '+ 'x n)))
ADDN
CL-USER> (ff 'addn 7)
(LAMBDA (X) (+ X 7))
CL-USER> (ff (addn 3) 7)
; Evaluation aborted on #<TYPE-ERROR #x1A7B00F6>.
CL-USER> (type-of (addn 3))
CONS
CL-USER> (ff (coerce (addn 3) 'function) 7)
10
Now it works, after coercing the list to a function.
|
|
0
|
|
|
|
Reply
|
vanek (323)
|
10/25/2010 11:14:21 PM
|
|
On Oct 25, 7:14=A0pm, vanekl <va...@acd.net> wrote:
> On Oct 25, 7:02=A0pm, Andy Venikov <swojchelo...@gmail.com> wrote:
>
>
>
>
>
>
>
>
>
> > On 10/25/2010 6:43 PM, vanekl wrote:
> > <snip>
>
> > >> (defun f (op i)
> > >> =A0 =A0 =A0 (funcall op i))
>
> > >> (defun addn (n)
> > >> =A0 =A0 (list 'lambda '(x) (list '+ 'n n)))
>
> > >> ;;This is supposed to evaluate to 10
> > >> (f (addn 3) 7)
>
> > <snip>
>
> > > CL-USER> =A0(lisp-implementation-type)
> > > "Clozure Common Lisp"
> > > CL-USER> =A0(lisp-implementation-version)
> > > "Version 1.6-dev-r14370M-trunk =A0(LinuxX8632)"
> > > CL-USER> =A0(defun ff (op i)
> > > =A0 =A0(funcall op i))
> > > FF
> > > CL-USER> =A0(defun addn (n)
> > > =A0 =A0(lambda (x) (+ x n)))
> > > ADDN
> > > CL-USER> =A0(ff 'addn 7)
> > > #<COMPILED-LEXICAL-CLOSURE (:INTERNAL ADDN) #x1A7E72BE>
> > > CL-USER> =A0(ff (addn 3) 7)
> > > 10
>
> > But isn't this code different from the original?
> > In your case function ff returns the result of evaluating S-expression
> > (lambda (x) (+ x n)) which will be a function-form. In the original
> > version, addn was returning the S-expression unevaluated. Someone has t=
o
> > evaluate it to construct a function object, right?
>
> > Thanks,
> > =A0 =A0 Andy.
>
> Yes, you're right, the code is a bit different. Instead of evaluating
> a function, it's trying to evaluate a CONS (list).
>
> So, instead of creating a function, create a list:
> CL-USER> (defun addn (n)
> =A0;; (lambda (x) (+ x n)))
> (list 'lambda '(x) (list '+ 'x n)))
> ADDN
> CL-USER> (ff 'addn 7)
> (LAMBDA (X) (+ X 7))
> CL-USER> (ff (addn 3) 7)
> ; Evaluation aborted on #<TYPE-ERROR #x1A7B00F6>.
> CL-USER> (type-of (addn 3))
> CONS
> CL-USER> (ff (coerce (addn 3) 'function) 7)
> 10
>
> Now it works, after coercing the list to a function.
Or you could make it a little more elegant and rewrite 'ff':
CL-USER> (defun ff (op i)
(funcall (if (typep op 'function)
op
(coerce op 'function))
i))
FF
CL-USER> (ff (addn 3) 7)
10
|
|
0
|
|
|
|
Reply
|
vanek (323)
|
10/25/2010 11:21:14 PM
|
|
On 10/25/2010 7:14 PM, vanekl wrote:
<snip>
>> But isn't this code different from the original?
>> In your case function ff returns the result of evaluating S-expression
>> (lambda (x) (+ x n)) which will be a function-form. In the original
>> version, addn was returning the S-expression unevaluated. Someone has to
>> evaluate it to construct a function object, right?
>>
>> Thanks,
>> Andy.
>
> Yes, you're right, the code is a bit different. Instead of evaluating
> a function, it's trying to evaluate a CONS (list).
>
> So, instead of creating a function, create a list:
> CL-USER> (defun addn (n)
> ;; (lambda (x) (+ x n)))
> (list 'lambda '(x) (list '+ 'x n)))
> ADDN
> CL-USER> (ff 'addn 7)
> (LAMBDA (X) (+ X 7))
> CL-USER> (ff (addn 3) 7)
> ; Evaluation aborted on #<TYPE-ERROR #x1A7B00F6>.
> CL-USER> (type-of (addn 3))
> CONS
> CL-USER> (ff (coerce (addn 3) 'function) 7)
> 10
>
> Now it works, after coercing the list to a function.
Thanks for the reply.
Interesting, will "coercing" invoke an eval?
|
|
0
|
|
|
|
Reply
|
swojchelowek1 (8)
|
10/25/2010 11:23:33 PM
|
|
On Oct 25, 7:23=A0pm, Andy Venikov <swojchelo...@gmail.com> wrote:
> On 10/25/2010 7:14 PM, vanekl wrote:
> <snip>
>
>
>
>
>
>
>
>
>
> >> But isn't this code different from the original?
> >> In your case function ff returns the result of evaluating S-expression
> >> (lambda (x) (+ x n)) which will be a function-form. In the original
> >> version, addn was returning the S-expression unevaluated. Someone has =
to
> >> evaluate it to construct a function object, right?
>
> >> Thanks,
> >> =A0 =A0 =A0Andy.
>
> > Yes, you're right, the code is a bit different. Instead of evaluating
> > a function, it's trying to evaluate a CONS (list).
>
> > So, instead of creating a function, create a list:
> > CL-USER> =A0(defun addn (n)
> > =A0 ;; (lambda (x) (+ x n)))
> > (list 'lambda '(x) (list '+ 'x n)))
> > ADDN
> > CL-USER> =A0(ff 'addn 7)
> > (LAMBDA (X) (+ X 7))
> > CL-USER> =A0(ff (addn 3) 7)
> > ; Evaluation aborted on #<TYPE-ERROR #x1A7B00F6>.
> > CL-USER> =A0(type-of (addn 3))
> > CONS
> > CL-USER> =A0(ff (coerce (addn 3) 'function) 7)
> > 10
>
> > Now it works, after coercing the list to a function.
>
> Thanks for the reply.
> Interesting, will "coercing" invoke an eval?
No, it just changes a list into something that can be evaluated by
'funcall'.
'funcall' is where most of the heavy lifting (evaluation) is being
performed.
|
|
0
|
|
|
|
Reply
|
vanek (323)
|
10/25/2010 11:25:45 PM
|
|
On 10/25/2010 7:25 PM, vanekl wrote:
> On Oct 25, 7:23 pm, Andy Venikov<swojchelo...@gmail.com> wrote:
>> On 10/25/2010 7:14 PM, vanekl wrote:
>> <snip>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>>> But isn't this code different from the original?
>>>> In your case function ff returns the result of evaluating S-expression
>>>> (lambda (x) (+ x n)) which will be a function-form. In the original
>>>> version, addn was returning the S-expression unevaluated. Someone has to
>>>> evaluate it to construct a function object, right?
>>
>>>> Thanks,
>>>> Andy.
>>
>>> Yes, you're right, the code is a bit different. Instead of evaluating
>>> a function, it's trying to evaluate a CONS (list).
>>
>>> So, instead of creating a function, create a list:
>>> CL-USER> (defun addn (n)
>>> ;; (lambda (x) (+ x n)))
>>> (list 'lambda '(x) (list '+ 'x n)))
>>> ADDN
>>> CL-USER> (ff 'addn 7)
>>> (LAMBDA (X) (+ X 7))
>>> CL-USER> (ff (addn 3) 7)
>>> ; Evaluation aborted on #<TYPE-ERROR #x1A7B00F6>.
>>> CL-USER> (type-of (addn 3))
>>> CONS
>>> CL-USER> (ff (coerce (addn 3) 'function) 7)
>>> 10
>>
>>> Now it works, after coercing the list to a function.
>>
>> Thanks for the reply.
>> Interesting, will "coercing" invoke an eval?
>
> No, it just changes a list into something that can be evaluated by
> 'funcall'.
> 'funcall' is where most of the heavy lifting (evaluation) is being
> performed.
Oh, I see. So basically funcall will have to interpret the S-expression
as a function (or invoke a compiler in the compiled code)?
Does it mean that one should be careful with it if performance matters?
|
|
0
|
|
|
|
Reply
|
swojchelowek1 (8)
|
10/25/2010 11:28:34 PM
|
|
On Oct 25, 7:28=A0pm, Andy Venikov <swojchelo...@gmail.com> wrote:
> On 10/25/2010 7:25 PM, vanekl wrote:
>
>
>
>
>
>
>
>
>
> > On Oct 25, 7:23 pm, Andy Venikov<swojchelo...@gmail.com> =A0wrote:
> >> On 10/25/2010 7:14 PM, vanekl wrote:
> >> <snip>
>
> >>>> But isn't this code different from the original?
> >>>> In your case function ff returns the result of evaluating S-expressi=
on
> >>>> (lambda (x) (+ x n)) which will be a function-form. In the original
> >>>> version, addn was returning the S-expression unevaluated. Someone ha=
s to
> >>>> evaluate it to construct a function object, right?
>
> >>>> Thanks,
> >>>> =A0 =A0 =A0 Andy.
>
> >>> Yes, you're right, the code is a bit different. Instead of evaluating
> >>> a function, it's trying to evaluate a CONS (list).
>
> >>> So, instead of creating a function, create a list:
> >>> CL-USER> =A0 =A0(defun addn (n)
> >>> =A0 =A0;; (lambda (x) (+ x n)))
> >>> (list 'lambda '(x) (list '+ 'x n)))
> >>> ADDN
> >>> CL-USER> =A0 =A0(ff 'addn 7)
> >>> (LAMBDA (X) (+ X 7))
> >>> CL-USER> =A0 =A0(ff (addn 3) 7)
> >>> ; Evaluation aborted on #<TYPE-ERROR #x1A7B00F6>.
> >>> CL-USER> =A0 =A0(type-of (addn 3))
> >>> CONS
> >>> CL-USER> =A0 =A0(ff (coerce (addn 3) 'function) 7)
> >>> 10
>
> >>> Now it works, after coercing the list to a function.
>
> >> Thanks for the reply.
> >> Interesting, will "coercing" invoke an eval?
>
> > No, it just changes a list into something that can be evaluated by
> > 'funcall'.
> > 'funcall' is where most of the heavy lifting (evaluation) is being
> > performed.
>
> Oh, I see. So basically funcall will have to interpret the S-expression
> as a function (or invoke a compiler in the compiled code)?
> Does it mean that one should be careful with it if performance matters?
No, funcall is very fast. It's roughly as fast as making any other
function call.
|
|
0
|
|
|
|
Reply
|
vanek (323)
|
10/25/2010 11:30:00 PM
|
|
Andy Venikov <swojchelowek@gmail.com> writes:
> (defun f (op i)
> (funcall op i))
>
> (defun addn (n)
> (list 'lambda '(x) (list '+ 'n n)))
>
> ;;This is supposed to evaluate to 10
> (f (addn 3) 7)
As far as I can tell, the author got confused and wrote non-conforming
code.
(defun addn (n)
(lambda (x) (+ x n)))
(funcall (addn 3) 3)
seems more reasonable to me.
|
|
0
|
|
|
|
Reply
|
Paul
|
10/26/2010 12:08:58 AM
|
|
Andy Venikov <swojchelowek@gmail.com> writes:
> On 10/25/2010 7:25 PM, vanekl wrote:
>> On Oct 25, 7:23 pm, Andy Venikov<swojchelo...@gmail.com> wrote:
>>> On 10/25/2010 7:14 PM, vanekl wrote:
>>> <snip>
>>>> Now it works, after coercing the list to a function.
>>>
>>> Thanks for the reply.
>>> Interesting, will "coercing" invoke an eval?
>>
>> No, it just changes a list into something that can be evaluated by
>> 'funcall'.
>> 'funcall' is where most of the heavy lifting (evaluation) is being
>> performed.
>
> Oh, I see. So basically funcall will have to interpret the
> S-expression as a function (or invoke a compiler in the compiled
> code)?
> Does it mean that one should be careful with it if performance matters?
FUNCALL calls the function, using APPLY.
APPLY may just jump to the function code if it's compiled to native code,
or run byte-code virtual machine interpreter if it's compiled to bytecode,
or run the interpreter if the function is to be interpreted.
COERCE may call COMPILE to generate a compiled version of the function,
or may just implement the minimal-compilation specified, or may defer it
to the interpreter.
So in terms of performance, when using COERCE, the repartition depends
entirely on the implementation.
If you know that your implementation has a compiler (they almost all of
them have one), then you could use COMPILE instead of COERCE, to ensure
an early compilation.
And of course, if you don't call repeatitively your function, it might
be better to interpreter it than to have the overhead of compiling it.
--
__Pascal Bourguignon__ http://www.informatimago.com/
|
|
0
|
|
|
|
Reply
|
pjb
|
10/26/2010 3:52:04 AM
|
|
Paul Donnelly <paul-donnelly@sbcglobal.net> writes:
> Andy Venikov <swojchelowek@gmail.com> writes:
>
>> (defun f (op i)
>> (funcall op i))
>>
>> (defun addn (n)
>> (list 'lambda '(x) (list '+ 'n n)))
>>
>> ;;This is supposed to evaluate to 10
>> (f (addn 3) 7)
>
> As far as I can tell, the author got confused and wrote non-conforming
> code.
>
> (defun addn (n)
> (lambda (x) (+ x n)))
>
> (funcall (addn 3) 3)
>
> seems more reasonable to me.
In old lisps, and eg. in emacs lisp, it is possible to funcall a list
starting with lambda.
In emacs:
(eval '(funcall '(lambda () (insert "Hello!\n"))))
Hello!
nil
--
__Pascal Bourguignon__ http://www.informatimago.com/
|
|
0
|
|
|
|
Reply
|
pjb
|
10/26/2010 3:53:20 AM
|
|
pjb@informatimago.com (Pascal J. Bourguignon) writes:
> Paul Donnelly <paul-donnelly@sbcglobal.net> writes:
>
>> Andy Venikov <swojchelowek@gmail.com> writes:
>>
>>> (defun f (op i)
>>> (funcall op i))
>>>
>>> (defun addn (n)
>>> (list 'lambda '(x) (list '+ 'n n)))
>>>
>>> ;;This is supposed to evaluate to 10
>>> (f (addn 3) 7)
>>
>> As far as I can tell, the author got confused and wrote non-conforming
>> code.
>>
>> (defun addn (n)
>> (lambda (x) (+ x n)))
>>
>> (funcall (addn 3) 3)
>>
>> seems more reasonable to me.
>
> In old lisps, and eg. in emacs lisp, it is possible to funcall a list
> starting with lambda.
>
> In emacs:
>
> (eval '(funcall '(lambda () (insert "Hello!\n"))))
> Hello!
> nil
Out of curiousity, are there any Common Lisps that provide this?
|
|
0
|
|
|
|
Reply
|
Paul
|
10/26/2010 4:56:25 AM
|
|
Paul Donnelly <paul-donnelly@sbcglobal.net> writes:
> pjb@informatimago.com (Pascal J. Bourguignon) writes:
>
>> Paul Donnelly <paul-donnelly@sbcglobal.net> writes:
>>
>>> Andy Venikov <swojchelowek@gmail.com> writes:
>>>
>>>> (defun f (op i)
>>>> (funcall op i))
>>>>
>>>> (defun addn (n)
>>>> (list 'lambda '(x) (list '+ 'n n)))
>>>>
>>>> ;;This is supposed to evaluate to 10
>>>> (f (addn 3) 7)
>>>
>>> As far as I can tell, the author got confused and wrote non-conforming
>>> code.
>>>
>>> (defun addn (n)
>>> (lambda (x) (+ x n)))
>>>
>>> (funcall (addn 3) 3)
>>>
>>> seems more reasonable to me.
>>
>> In old lisps, and eg. in emacs lisp, it is possible to funcall a list
>> starting with lambda.
>>
>> In emacs:
>>
>> (eval '(funcall '(lambda () (insert "Hello!\n"))))
>> Hello!
>> nil
>
> Out of curiousity, are there any Common Lisps that provide this?
A Common Lisp _implementation_ could provide this feature as an
extension.
But:
(eval '(funcall '(lambda () ...)))
are not conformant Common Lisp forms.
Of the four implementations I have on my system, only ECL considers the
lambda form to be a function.
[pjb@kuiper :0.0 lisp]$ clall '(eval (quote (funcall (quote (lambda () (+ 1 2))))))'
========================================================================
Clozure Common Lisp Version 1.5 (LinuxX8664)
Evaluation of
(EVAL '(FUNCALL '(LAMBDA NIL (+ 1 2))))
produced nothing on *STANDARD-OUTPUT*
produced nothing on *ERROR-OUTPUT*
produced the following error:
#<TYPE-ERROR #x3020005D3E9D>
(LAMBDA NIL (+ 1 2)) is not of type (OR SYMBOL FUNCTION), and can't be FUNCALLed or APPLYed
produced the following values:
-->
========================================================================
CLISP 2.48 (2009-07-28) (built 3496707691) (memory 3496707846)
Evaluation of
(EVAL '(FUNCALL '(LAMBDA NIL (+ 1 2))))
produced nothing on *STANDARD-OUTPUT*
produced nothing on *ERROR-OUTPUT*
produced the following error:
#<SIMPLE-TYPE-ERROR #x000333FA22D0>
FUNCALL: argument (LAMBDA NIL (+ 1 2)) is not a function.
To get a function in the current environment, write (FUNCTION ...).
To get a function in the global environment, write (COERCE '... 'FUNCTION).
produced the following values:
-->
;;; Loading "/tmp/clall-4611.lisp"
========================================================================
ECL 9.12.3
Evaluation of
(EVAL '(FUNCALL '(LAMBDA () (+ 1 2))))
produced nothing on *STANDARD-OUTPUT*
produced nothing on *ERROR-OUTPUT*
produced no error
produced the following values:
--> 3
; loading system definition from
; /usr/share/common-lisp/systems/asdf-binary-locations.asd into
; #<PACKAGE "ASDF0">
; registering #<SYSTEM ASDF-BINARY-LOCATIONS {1002BFA1B1}> as
; ASDF-BINARY-LOCATIONS
========================================================================
SBCL 1.0.19-gentoo
Evaluation of
(EVAL '(FUNCALL '(LAMBDA () (+ 1 2))))
produced nothing on *STANDARD-OUTPUT*
produced nothing on *ERROR-OUTPUT*
produced the following error:
#<TYPE-ERROR {1002B6CE61}>
The value (LAMBDA () (+ 1 2)) is not of type (OR FUNCTION SYMBOL).
produced the following values:
-->
========================================================================
--
__Pascal Bourguignon__ http://www.informatimago.com/
|
|
0
|
|
|
|
Reply
|
pjb
|
10/26/2010 5:55:41 AM
|
|
On 2010-10-26 00:23:33 +0100, Andy Venikov said:
>
> Thanks for the reply.
> Interesting, will "coercing" invoke an eval?
sort-of. What it will do is look for either a symbol (in which case it
will return the global function definition) or a list whose first
element is LAMBDA (in which case it will return a lexical closure in
the null environment). The second case can cause arbitrary evaluation
to happen at the time COERCE is called, I am pretty sure (something
like (coerce '(lambda () (load-time-value (progn (print "hi") 1)))) I
think is an example of this).
However, what you are thinking may be that it just evaluates its
argument to get a function, and that's not the case. It happens, now,
to be the case that LAMBDA has a macro definition which means that
(lambda ...) constructs a function, but COERCE doesn't care about that,
and it worked before LAMBDA had this definition, which is a relatively
late addition to CL.
The definition of what it does can be found here:
http://www.lispworks.com/documentation/HyperSpec/Body/f_coerce.htm.
|
|
0
|
|
|
|
Reply
|
Tim
|
10/26/2010 8:04:02 AM
|
|
Tim Bradshaw <tfb@tfeb.org> wrote:
+---------------
| Andy Venikov said:
| > Interesting, will "coercing" invoke an eval?
|
| sort-of. What it will do is look for either a symbol (in which case it
| will return the global function definition) or a list whose first
| element is LAMBDA (in which case it will return a lexical closure in
| the null environment). The second case can cause arbitrary evaluation
| to happen at the time COERCE is called, I am pretty sure (something
| like (coerce '(lambda () (load-time-value (progn (print "hi") 1)))) I
| think is an example of this).
+---------------
Minor nit to avoid confusing OP: the COERCE needs a 2nd arg
of 'FUNCTION here:
cmu> (coerce '(lambda () (load-time-value (progn (print "hi") 1)))
'function)
#<Interpreted Function (LAMBDA () (LOAD-TIME-VALUE #)) {489A2509}>
cmu> (funcall *)
"hi"
1
cmu> (funcall **)
1
cmu>
Note that the second FUNCALL didn't print "hi", since CMUCL
[which I'm using above] actually does very little during the
COERCE [it likewise does very little during the execution of
an interpreted DEFUN], delaying "conversion" [minimal compilation]
of the LAMBDA form to full internal interpreter form until the
first time the function is called. It is during this "conversion"
that the LOAD-TIME-VALUE was evaluated, hence the printing of "hi"
during the first FUNCALL and not the second.
Now let's actually compile it:
cmu> (compile nil ***)
; Compiling LAMBDA NIL:
; Compiling Top-Level Form:
"hi"
#<Function "LAMBDA NIL" {489B3021}>
NIL
NIL
cmu> (funcall *)
1
cmu> (funcall **)
1
cmu>
Note that the function is re-converted during full compilation
to native code, hence the printing of "hi" during compilation
and *not* during the first or second FUNCALL of the result.
You may very well get different results [by which I mean when
"hi" gets printed or not] in other CL implementations.
-Rob
-----
Rob Warnock <rpw3@rpw3.org>
627 26th Avenue <URL:http://rpw3.org/>
San Mateo, CA 94403 (650)572-2607
|
|
0
|
|
|
|
Reply
|
rpw3
|
10/26/2010 9:29:45 AM
|
|
On 2010-10-26 10:29:45 +0100, Rob Warnock said:
> You may very well get different results [by which I mean when
> "hi" gets printed or not] in other CL implementations.
Yes, I'm sure that is correct.
|
|
0
|
|
|
|
Reply
|
Tim
|
10/26/2010 10:03:31 AM
|
|
??>> No, it just changes a list into something that can be evaluated by
??>> 'funcall'.
??>> 'funcall' is where most of the heavy lifting (evaluation) is being
??>> performed.
I don't think it is correct...
AV> Oh, I see. So basically funcall will have to interpret the S-expression
AV> as a function (or invoke a compiler in the compiled code)?
No, actually funcall is a very simple operation like CPU's `call`
instruction -- it just tells execution engine to start executing function at
certain address (with certain arguments).
The rest depends on execution engine.
I guess for implementation which work with native code funcall will be
compiled to an instruction like CALL or JMP (with additional handling of
parameters and return values, of course).
And for bytecode interpreter it will do analogous thing...
While it is theoretically possible that implementation uses just-in-time
compilation strategy, it doesn't really mean that funcall itself is
expensive.
Conceptually, you can think that (coerce ... 'function), (compile ...) or
(eval ...) do "the magic" to convert code to function.
How it works in practice depends on implementation.
AV> Does it mean that one should be careful with it if performance
AV> matters?
No, performance overhead is very low -- like an additional indirection
overhead, if any...
If you care about performance maybe it is better to call (compile ...)
instead of (coerce ... 'function).
In some implementations they are equivalent, but in other ones compiled
functions work a lot faster.
|
|
0
|
|
|
|
Reply
|
Captain
|
10/26/2010 10:18:25 AM
|
|
CO> I guess for implementation which work with native code funcall will be
CO> compiled to an instruction like CALL or JMP (with additional handling
CO> of parameters and return values, of course).
Here's, for example, listings from SBCL:
CL-USER> (defun my-funcall (x)
(declare (optimize (speed 3))
(function x))
(funcall x))
MY-FUNCALL
CL-USER> (disassemble 'my-funcall)
; 0B4C1AA9: 31C9 XOR ECX, ECX ;
no-arg-parsing entry point
; AB: FF75F8 PUSH DWORD PTR [EBP-8]
; AE: FF60FF JMP DWORD PTR [EAX-1]
; B1: 90 NOP
....
So if it knows that parameter x is a function it just does JMP.
If it does not know that it has to call SB-KERNEL:%COERCE-CALLABLE-TO-FUN
first to get address of the function:
; in: LAMBDA NIL
; (FUNCALL X)
; --> SB-C::%FUNCALL THE
; ==>
; (SB-KERNEL:%COERCE-CALLABLE-TO-FUN FUNCTION)
;
; note: unable to
; optimize away possible call to FDEFINITION at runtime
; due to type uncertainty:
; The first argument is a (OR FUNCTION SYMBOL), not a FUNCTION.
; 0B5A6F1F: 8BC2 MOV EAX, EDX ;
no-arg-parsing entry point
; 21: 2407 AND AL, 7
; 23: 3C05 CMP AL, 5
; 25: 7416 JEQ L0
; 27: 81FA0B001001 CMP EDX, 17825803
; 2D: 740E JEQ L0
; 2F: 8BC2 MOV EAX, EDX
; 31: 2407 AND AL, 7
; 33: 3C07 CMP AL, 7
; 35: 752C JNE L2
; 37: 807AF93E CMP BYTE PTR [EDX-7], 62
; 3B: 7526 JNE L2
; 3D: L0: 8BDC MOV EBX, ESP
; 3F: 83EC0C SUB ESP, 12
; 42: 8B05F06E5A0B MOV EAX, [#xB5A6EF0] ;
#<FDEFINITION object for SB-KERNEL:%COERCE-CALLABLE-TO-FUN>
; 48: B904000000 MOV ECX, 4
; 4D: 896BFC MOV [EBX-4], EBP
; 50: 8BEB MOV EBP, EBX
; 52: FF5005 CALL DWORD PTR [EAX+5]
; 55: 7302 JNB L1
; 57: 8BE3 MOV ESP, EBX
; 59: L1: 8BC2 MOV EAX, EDX
; 5B: 31C9 XOR ECX, ECX
; 5D: FF75F8 PUSH DWORD PTR [EBP-8]
; 60: FF60FF JMP DWORD PTR [EAX-1]
And then you see same JMP.
|
|
0
|
|
|
|
Reply
|
udodenko (1040)
|
10/26/2010 11:15:19 AM
|
|
pjb@informatimago.com (Pascal J. Bourguignon) writes:
> In old lisps, and eg. in emacs lisp, it is possible to funcall a list
> starting with lambda.
This was once true in Common Lisp: CLtL 2.13 says (in a section marked
with change bars):
: A /function/ is anything that may be correctly given to the |funcall|
: or |apply| function, and is to be executed as code when arguments are
: supplied. ... A lambda-expression (a list whose car is the symbol
: |lambda|) may serve as a function.
-- [mdw]
|
|
0
|
|
|
|
Reply
|
Mark
|
10/26/2010 1:22:41 PM
|
|
|
19 Replies
103 Views
(page loaded in 3.848 seconds)
Similiar Articles: Fill between curves that are functions, not data series - comp ...Hi all, I am wondering whether one can use the fill between curves style not only with data series but also with analytical functions (in my case ... Best numerical integration technique for experimental data - comp ...Hello, I'm trying to solve a 1st order ODE that has experimental data as part of the function. cumtrapz will not suffice because I need to call 2 ... Update Data using callback of Uitable - comp.soft-sys.matlab ...... sensor in a different function and so when you existed that function your sensor values were lost. Try setting handles.uitable1 in the same function as the sensor data. How to c the wavread function.. - comp.soft-sys.matlabHi all, Can i have your advise how can i c the background code of wavread function? As i wish to c how the sound data x is retrieved from the wa... fitting a circular arc for 2d data points - comp.soft-sys.matlab ...Plotting 3D of a function with circular domain - comp.soft-sys ... How to plot isolines from sampled data? - comp ... plot 2d in 3d - comp.soft-sys.matlab Hello ... soft ... Turning experimental data into a piecewise function - comp.soft ...I am working with a tensile tester that performs an intermittent load-hold test profile. The load is steadily increased, then held for some period of... 2D interpolation - comp.soft-sys.matlabThis chapter describes Cgal 's interpolation package which implements natural neighbor coordinate functions as well as different methods for scattered data ... Smoothing image data - comp.soft-sys.matlabI want to make a measurement on some image data which requires it to be smooth. I have a noisy image. With 1D data I would use the "smooth" function. ... convert mat files (struct) to ascii text files / save data as ...I'm using a script that saves data (x,y) as .mat files in struct format. ... You could always try writing the data using other functions See: dlmwrite, csvwrite, xlswrite... Count the number occurence - comp.soft-sys.matlabI am looking for some already implemented function as I have to run this code for many data so code efficiency is really important. I would like to thank you in ... Using matlab to do modelling and curve fitting using Data from ...Fit a step function to set of x,y data - comp ... ... MATLAB how do you ... How To Use Distributions In Excel - EasyFit - Distribution Fitting ... Passing a non-temporary array to a proc fcmp function - comp.soft ...Hi there, I just learned about creating functions using proc fcmp that can be called in the data step. I would like to pass a non-temporary array... Embedded matlab function in simulink for mutiple inputs and ...How to create an example Simulink model with a MATLAB Function block ... Connecting Multi-Rate Buses to ... By default, function inputs and outputs inherit their data ... Radial Basis Function Neural Network Tool Box - comp.soft-sys ...Hi Experts, I'm trying to use the NN toolbox with RBF training functions. However, I was not able to click the train icon to train my data set. I ... Fastest way to save data? - comp.soft-sys.matlabIs there some other function I could use ? For reference the data comes from the 'scope in 15MB chunks which is 15e6 samples at 1 byte per sample, when this is assigned ... Functions as Data | JavaScript, JavaScript…In JavaScript, functions can be assigned to variables, and variables are data. This is powerful. Here’s a simple example:-var say = alert; say("hello ... Functions as Data - EECS Instructional Support Group Home Page1. Nested Functions. You can define functions within other functions, if you want. Each new level gets its own set of local variables. Here is a classic example: 7/11/2012 6:57:52 AM
|