I have implemented a small fexpr interpreter in Common Lisp based on Kernel http://web.cs.wpi.edu/~jshutt/kernel.html. Right now it's a Lisp 1, but I am considering trying to make it a more idiomatic extension of Common Lisp by making it a Lisp 2.
Part of the Lisp 2-ness of the Common Lisp evaluator is that the car of a form must name a function, macro, or special form. This name is either a symbol bound in the function name space, or a lambda expression. However, Kernel just requires the car evaluate to a combiner (this is what Kernel calls a generic operator). Obviously, in a Lisp 2, a symbol would evaluate to the value bound to it in the function name space. However, consider the following:
((returns-a-function) arg arg ...)
Would it be reasonable to allow this as a legal form as well?
I'm not arguing Common Lisp should work this way, but I seems to make sense in the context of a Kernel like evaluator.
Matt
On 25 May 2011, at 04:51, Matthew D. Swank wrote:
I have implemented a small fexpr interpreter in Common Lisp based on Kernel http://web.cs.wpi.edu/~jshutt/kernel.html. Right now it's a Lisp 1, but I am considering trying to make it a more idiomatic extension of Common Lisp by making it a Lisp 2.
Part of the Lisp 2-ness of the Common Lisp evaluator is that the car of a form must name a function, macro, or special form. This name is either a symbol bound in the function name space, or a lambda expression. However, Kernel just requires the car evaluate to a combiner (this is what Kernel calls a generic operator). Obviously, in a Lisp 2, a symbol would evaluate to the value bound to it in the function name space. However, consider the following:
((returns-a-function) arg arg ...)
Would it be reasonable to allow this as a legal form as well?
I'm not arguing Common Lisp should work this way, but I seems to make sense in the context of a Kernel like evaluator.
_If_ (returns-a-function) indeed returns a function, then this could be ok. But what if it doesn't return a function? What if it is a macro that returns just a symbol? Do you want to risk that ((return-something) ...) has a different meaning than (funcall (return-something) ...)? This is potentially confusing and could lead to code that is hard to debug...
Pascal
-- Pascal Costanza The views expressed in this email are my own, and not those of my employer.
On Wed, 25 May 2011 07:34:22 +0200, Pascal Costanza said:
On 25 May 2011, at 04:51, Matthew D. Swank wrote:
I have implemented a small fexpr interpreter in Common Lisp based on Kernel http://web.cs.wpi.edu/~jshutt/kernel.html. Right now it's a Lisp 1, but I am considering trying to make it a more idiomatic extension of Common Lisp by making it a Lisp 2.
Part of the Lisp 2-ness of the Common Lisp evaluator is that the car of a form must name a function, macro, or special form. This name is either a symbol bound in the function name space, or a lambda expression. However, Kernel just requires the car evaluate to a combiner (this is what Kernel calls a generic operator). Obviously, in a Lisp 2, a symbol would evaluate to the value bound to it in the function name space. However, consider the following:
((returns-a-function) arg arg ...)
Would it be reasonable to allow this as a legal form as well?
I'm not arguing Common Lisp should work this way, but I seems to make sense in the context of a Kernel like evaluator.
_If_ (returns-a-function) indeed returns a function, then this could be ok. But what if it doesn't return a function? What if it is a macro that returns just a symbol? Do you want to risk that ((return-something) ...) has a different meaning than (funcall (return-something) ...)? This is potentially confusing and could lead to code that is hard to debug...
Maybe no harder than other Lisp-2's :-)
It seems like an interesting extension of the term "Lisp-2" -- as well as just specifying different namespaces, the proposal is to have a different evaluator for the car of the form. In fact, CL already has one, but it is very limited.
If that evaluator allows macro forms, then a macro that expands to a symbol should work as if the symbol was used directly. If you use such a macro with (funcall (return-something) ...), then you are using the regular evaluator for the macro form.
On May 25, 2011, at 7:45 AM, Martin Simmons wrote:
It seems like an interesting extension of the term "Lisp-2" -- as well as just specifying different namespaces, the proposal is to have a different evaluator for the car of the form. In fact, CL already has one, but it is very limited.
If I'm not mistaken, this extension has already been implemented for ccl by Ron Garret:
http://www.flownet.com/ron/lisp/combination-hook.lisp
warmest regards,
Ralph
Raffael Cavallaro raffaelcavallaro@me.com
On 05/25/2011 06:45 AM, Martin Simmons wrote:
It seems like an interesting extension of the term "Lisp-2" -- as well as just specifying different namespaces, the proposal is to have a different evaluator for the car of the form. In fact, CL already has one, but it is very limited.
If that evaluator allows macro forms, then a macro that expands to a symbol should work as if the symbol was used directly. If you use such a macro with (funcall (return-something) ...), then you are using the regular evaluator for the macro form.
Well, the concrete interpreter I am working on uses a form of fexprs as the fundamental operators in the language. There wouldn't be macro 'phase' as such to consider. For ((returns-something) arg ...) to work like (funcall (returns-something) arg ...) the evaluator, in addition to evaluating compound expressions that occur in the car of a form, would need to coerce those expressions that evaluate to symbols.
In a purely Common Lisp context, if the expression in the car is "macros all the way down", you could make a case that form as a whole should be evaluated in a macro context. That would be interesting to debug as well.
Matt
Pascal Costanza <pc@...> writes:
On 25 May 2011, at 04:51, Matthew D. Swank wrote:
However, consider the following:
((returns-a-function) arg arg ...)
Would it be reasonable to allow this as a legal form as well?
I'm not arguing Common Lisp should work this way, but I seems to make sense in the context of a Kernel like evaluator.
_If_ (returns-a-function) indeed returns a function, then this could be ok. But what if it doesn't return a function? What if it is a macro that returns just a symbol? Do you want to risk that ((return-something) ...) has a different meaning than (funcall (return-something) ...)? This is potentially confusing and could lead to code that is hard to debug...
Yes you'd have to watch for symbols. The idiom would be to coerce values for use in the car:
((callable (returns-a-function?)) arg arg ...)
or stick to using funcall.
Matt
On Wed, May 25, 2011 at 4:45 PM, Matthew Swank akopa.gmane.poster@gmail.com wrote:
Pascal Costanza <pc@...> writes:
On 25 May 2011, at 04:51, Matthew D. Swank wrote:
However, consider the following:
((returns-a-function) arg arg ...)
Would it be reasonable to allow this as a legal form as well?
I'm not arguing Common Lisp should work this way, but I seems to make sense in the context of a Kernel like evaluator.
_If_ (returns-a-function) indeed returns a function, then this could be ok. But what if it doesn't return a function? What if it is a macro that returns just a symbol? Do you want to risk that ((return-something) ...) has a different meaning than (funcall (return-something) ...)? This is potentially confusing and could lead to code that is hard to debug...
Yes you'd have to watch for symbols. The idiom would be to coerce values for use in the car:
((callable (returns-a-function?)) arg arg ...)
or stick to using funcall.
While in principle I like such a thing, I think it doesn't play well with Lisp-2 (or more specifically, with Common Lisp). If ((whatever) ...) is a valid expression, then one would expect (let ((foo (whatever))) (foo ...)) to be equivalent, but it's not. And you can't use flet/labels for the same effect. Perhaps this is an oversight in flet: if it were a little more verbose - (flet ((x (lambda ...))) ...) - then you could also admit a more general form (flet ((x (returns-a-function))) ...). It would also be more symmetric with let. Of course, in general, the compiler would only optimize the former case, where the function is statically known. Hmm... this should go in my "CL++" wish list :D
Alessio
Alessio Stalla <alessiostalla@...> writes:
On Wed, May 25, 2011 at 4:45 PM, Matthew Swank <akopa.gmane.poster@...> wrote:
Pascal Costanza <pc@...> writes:
On 25 May 2011, at 04:51, Matthew D. Swank wrote:
However, consider the following:
((returns-a-function) arg arg ...)
Would it be reasonable to allow this as a legal form as well?
While in principle I like such a thing, I think it doesn't play well with Lisp-2 (or more specifically, with Common Lisp). If ((whatever) ...) is a valid expression, then one would expect (let ((foo (whatever))) (foo ...)) to be equivalent, but it's not. And you can't use flet/labels for the same effect.
Well, let bindings could be extended to use an operator to specify the namespace:
(let (((function foo) (lambda (arg ...) ...)) (bar (lambda (arg ...) ...))) (foo ...) (funcall bar ...))
and flet/labels would transform into a generalized let binding.
This would make the standard transformation of let -> function call a little problematic, however.
I suppose at the bottom of all this is an implied primitive binding operator for operators: perhaps flambda!
Matt
Hi
I don't think there is a reasonable objection to forbid a form like
((returns-something-funcallable arg1 arg2 ... argN) 1 2 3 ... N)
from "working as expected". As Martin pointed out, if the return value of the form is a "macro" then this would have to be interpreted in the "regular" evaluation regime.
As per "extending" LET there have been a lot of proposals... IMHO a nice one is to go the LOOP way :)
(LETS [var <symbol> <form>]* [fun (<name> <arglist> <body>)]* [labels (<name> <arglist> <body>)]* [values <list> <form>]* IN <body>)
Of course you can add some ways of extending the syntax by having something like
(def-lets-binding <tag> ...)
You get the idea....
Cheers -- MA
On May 25, 2011, at 17:51 , Matthew Swank wrote:
Alessio Stalla <alessiostalla@...> writes:
On Wed, May 25, 2011 at 4:45 PM, Matthew Swank <akopa.gmane.poster@...> wrote:
Pascal Costanza <pc@...> writes:
On 25 May 2011, at 04:51, Matthew D. Swank wrote:
However, consider the following:
((returns-a-function) arg arg ...)
Would it be reasonable to allow this as a legal form as well?
While in principle I like such a thing, I think it doesn't play well with Lisp-2 (or more specifically, with Common Lisp). If ((whatever) ...) is a valid expression, then one would expect (let ((foo (whatever))) (foo ...)) to be equivalent, but it's not. And you can't use flet/labels for the same effect.
Well, let bindings could be extended to use an operator to specify the namespace:
(let (((function foo) (lambda (arg ...) ...)) (bar (lambda (arg ...) ...))) (foo ...) (funcall bar ...))
and flet/labels would transform into a generalized let binding.
This would make the standard transformation of let -> function call a little problematic, however.
I suppose at the bottom of all this is an implied primitive binding operator for operators: perhaps flambda!
Matt
pro mailing list pro@common-lisp.net http://lists.common-lisp.net/cgi-bin/mailman/listinfo/pro
-- Marco Antoniotti, Associate Professor tel. +39 - 02 64 48 79 01 DISCo, Università Milano Bicocca U14 2043 http://bimib.disco.unimib.it Viale Sarca 336 I-20126 Milan (MI) ITALY
Please note that I am not checking my Spam-box anymore. Please do not forward this email without asking me first.
On Wed, May 25, 2011 at 9:40 PM, Marco Antoniotti antoniotti.marco@disco.unimib.it wrote:
Hi I don't think there is a reasonable objection to forbid a form like ((returns-something-funcallable arg1 arg2 ... argN) 1 2 3 ... N) from "working as expected".
Me neither ;)
As Martin pointed out, if the return value of the form is a "macro" then this would have to be interpreted in the "regular" evaluation regime. As per "extending" LET there have been a lot of proposals... IMHO a nice one is to go the LOOP way :) (LETS [var <symbol> <form>]* [fun (<name> <arglist> <body>)]* [labels (<name> <arglist> <body>)]* [values <list> <form>]* IN <body>) Of course you can add some ways of extending the syntax by having something like (def-lets-binding <tag> ...) You get the idea....
It's not about syntax, it's about a missing feature: the ability to bind a symbol's function "cell" to a value that's not known at compile time. To me, that's a limitation of the spec; given that we have funcall, it's obviously easy to implement and would be symmetrical to let. With such a feature, the gap between Lisp-1 and Lisp-2 would be effectively reduced:
(let ((list 42)) (flet ((list (compose #'nreverse #'list))) (list #'list list)))
=> (42 #<compiled-function (lambda (...) ...)>)
The code above is horrible, but you get the idea.
Alessio
On 05/25/2011 04:05 PM, Alessio Stalla wrote:
It's not about syntax, it's about a missing feature: the ability to bind a symbol's function "cell" to a value that's not known at compile time.
I've used this for pedagogical purposes: (defmacro f-let ((&rest bindings) &body body) (let* ((let-bindings (mapcar (lambda (binding) (list (gensym) (cadr binding))) bindings)) (flet-bindings (mapcar (lambda (binding let-binding) `(,(car binding) (&rest args) (apply ,(car let-binding) args))) bindings let-bindings))) `(let ,let-bindings (flet ,flet-bindings ,@body))))
but it hardly solves the problem.
On 26 May 2011, at 02:07, Matthew D. Swank wrote:
On 05/25/2011 04:05 PM, Alessio Stalla wrote:
It's not about syntax, it's about a missing feature: the ability to bind a symbol's function "cell" to a value that's not known at compile time.
I've used this for pedagogical purposes: (defmacro f-let ((&rest bindings) &body body) (let* ((let-bindings (mapcar (lambda (binding) (list (gensym) (cadr binding))) bindings)) (flet-bindings (mapcar (lambda (binding let-binding) `(,(car binding) (&rest args) (apply ,(car let-binding) args))) bindings let-bindings))) `(let ,let-bindings (flet ,flet-bindings ,@body))))
but it hardly solves the problem.
Why does it not solve the problem? Your definition shows that adding such a feature is just a matter of defining a macro, so it's more or less at the same level of adding a looping construct - it doesn't increase the expressiveness of the language (in the sense of Felleisen's macro-expressiveness).
So, what "problem" do you have in mind here?
Pascal
-- Pascal Costanza The views expressed in this email are my own, and not those of my employer.
On May 25, 2011, at 23:05 , Alessio Stalla wrote:
On Wed, May 25, 2011 at 9:40 PM, Marco Antoniotti antoniotti.marco@disco.unimib.it wrote:
Hi I don't think there is a reasonable objection to forbid a form like ((returns-something-funcallable arg1 arg2 ... argN) 1 2 3 ... N) from "working as expected".
Me neither ;)
As Martin pointed out, if the return value of the form is a "macro" then this would have to be interpreted in the "regular" evaluation regime. As per "extending" LET there have been a lot of proposals... IMHO a nice one is to go the LOOP way :) (LETS [var <symbol> <form>]* [fun (<name> <arglist> <body>)]* [labels (<name> <arglist> <body>)]* [values <list> <form>]* IN
<body>) Of course you can add some ways of extending the syntax by having something like (def-lets-binding <tag> ...) You get the idea....
It's not about syntax, it's about a missing feature: the ability to bind a symbol's function "cell" to a value that's not known at compile time. To me, that's a limitation of the spec; given that we have funcall, it's obviously easy to implement and would be symmetrical to let. With such a feature, the gap between Lisp-1 and Lisp-2 would be effectively reduced:
(let ((list 42)) (flet ((list (compose #'nreverse #'list))) (list #'list list)))
=> (42 #<compiled-function (lambda (...) ...)>)
The code above is horrible, but you get the idea.
Yep. This has been discussed before (*)... If I remember correctly you can get almost there by specifying differently what you are doing when dealing with the OP of a form, when this is a symbol. My recollection is that it is doable and that the rationale for not allowing it is mostly to make compiler writing easier (although I think that that should be a piece of cake today).
The problem is that you have to prioritize the namespace you are searching, thus ushering in a more complex set of rules for the programmer to remember. IMHO, this is not a very good reason to "leave it out" since it has been proved over and over again that languages which increase a programmer's self esteem are also those with the absolutely most convoluted access rules ever :) Plus these languages are also very successful :)
Cheers -- Marco
(*) It's in CLL.
-- Marco Antoniotti, Associate Professor tel. +39 - 02 64 48 79 01 DISCo, Università Milano Bicocca U14 2043 http://bimib.disco.unimib.it Viale Sarca 336 I-20126 Milan (MI) ITALY
Please note that I am not checking my Spam-box anymore. Please do not forward this email without asking me first.
On 25 May 2011, at 21:40, Marco Antoniotti wrote:
Hi
I don't think there is a reasonable objection to forbid a form like
((returns-something-funcallable arg1 arg2 ... argN) 1 2 3 ... N)
from "working as expected". As Martin pointed out, if the return value of the form is a "macro" then this would have to be interpreted in the "regular" evaluation regime.
The main issue I have with this is that at the moment, you have only explicit shifting operators (funcall/apply and function/symbol-function/fdefinition). A proposal like the one above would introduce implicit shifting.
You already have implicit shifting in the sense that placing a symbol in the car or any of the cdr positions is already enough to fetch something from the function or the value namespace. However, you can only do this with explicit function/variable names directly in the "user" code, or by constructing the correct s-expressions in macro definitions. With a proposal like the above, you would add another level of implicit shifting.
If I define a function, say (defun foo () 'bar), and a corresponding macro (defmacro foom () (foo)), then without explicit shifting and without macros, I can only use this to generate a variable name (baz (foom)), but not to generate a function name, because ((foom) baz) fails. With the proposal above, ((foom) baz) wouldn't fail. I prefer the explicitness of (funcall (foom) baz), especially because if you really, really, really want it implicit, you can still have it your way anyway.
Pascal
-- Pascal Costanza The views expressed in this email are my own, and not those of my employer.
On May 26, 2011, at 18:32 , Pascal Costanza wrote:
On 25 May 2011, at 21:40, Marco Antoniotti wrote:
Hi
I don't think there is a reasonable objection to forbid a form like
((returns-something-funcallable arg1 arg2 ... argN) 1 2 3 ... N)
from "working as expected". As Martin pointed out, if the return value of the form is a "macro" then this would have to be interpreted in the "regular" evaluation regime.
The main issue I have with this is that at the moment, you have only explicit shifting operators (funcall/apply and function/symbol-function/fdefinition). A proposal like the one above would introduce implicit shifting.
You already have implicit shifting in the sense that placing a symbol in the car or any of the cdr positions is already enough to fetch something from the function or the value namespace. However, you can only do this with explicit function/variable names directly in the "user" code, or by constructing the correct s-expressions in macro definitions. With a proposal like the above, you would add another level of implicit shifting.
If I define a function, say (defun foo () 'bar), and a corresponding macro (defmacro foom () (foo)), then without explicit shifting and without macros, I can only use this to generate a variable name (baz (foom)), but not to generate a function name, because ((foom) baz) fails. With the proposal above, ((foom) baz) wouldn't fail. I prefer the explicitness of (funcall (foom) baz), especially because if you really, really, really want it implicit, you can still have it your way anyway.
I think this are good reasons, but not enough to disallow the following:
(<symbol or form-returning-a-function-not-a-symbol or lambda-expression> ...)
We already have
((lambda (x) (+ x 42)) 0)
Why not have
((compose 'first 'rest) '(1 2 3))
This would complicate the call protocol and require more explanation, but I really don't see how it would harm the programmer.
Cheers -- MA
Pascal
-- Pascal Costanza The views expressed in this email are my own, and not those of my employer.
-- Marco Antoniotti, Associate Professor tel. +39 - 02 64 48 79 01 DISCo, Università Milano Bicocca U14 2043 http://bimib.disco.unimib.it Viale Sarca 336 I-20126 Milan (MI) ITALY
Please note that I am not checking my Spam-box anymore. Please do not forward this email without asking me first.
On 25.5.2011. 4:51, Matthew D. Swank wrote:
I have implemented a small fexpr interpreter in Common Lisp based on Kernel http://web.cs.wpi.edu/~jshutt/kernel.html. Right now it's a Lisp 1, but I am considering trying to make it a more idiomatic extension of Common Lisp by making it a Lisp 2.
Did you published anything online?
How would you estimate time / space requirements compared to original dynamically scoped FEXPRs?
On 06/04/2011 05:06 AM, Kazimir Majorinc wrote:
On 25.5.2011. 4:51, Matthew D. Swank wrote:
I have implemented a small fexpr interpreter in Common Lisp based on Kernel http://web.cs.wpi.edu/~jshutt/kernel.html. Right now it's a Lisp 1, but I am considering trying to make it a more idiomatic extension of Common Lisp by making it a Lisp 2.
Did you published anything online?
Not yet. I'm still making my way though the two relevant papers to see what can be adapted. My interpreter sticks pretty close to the exposition of vau-expressions in the first half of Dr Shutt's dissertation.
How would you estimate time / space requirements compared to original dynamically scoped FEXPRs?
I can't speak intelligently about that, except to note the overhead that statically scoped lisps have generally.
Matt