Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Erroneous warning when using eval to apply a procedure by value rather than by name. #902

Closed
Zambito1 opened this issue Mar 14, 2023 · 6 comments

Comments

@Zambito1
Copy link

(import (scheme base) (scheme eval))
(eval (list + 1 2) (environment))

The above eval should (and does) return 3. It is essentially the same as (apply + (list 1 2)), in the sense that + comes from the current lexical environment, rather than the environment parameter. eval warns about an "invalid operator in application", but I don't think it should.

The same error occurs whether the application is on an opcode or a procedure value.

> (eval (list + 1 2) (environment))
WARNING: invalid operator in application: (#<opcode "+"> 1 2)
3
> (eval (list display "test\n") (environment))
WARNING: invalid operator in application: (#<procedure display> "test\n")
test
@mnieper
Copy link
Collaborator

mnieper commented Mar 14, 2023

"It is an error" if the first argument to eval is not a Scheme datum value. (eval (list + 1 2) (environment ...)) is not standard Scheme; (eval (list '+ 1 2) (environment ...)) is.

+ does not "come from the current lexical environment" in the sense that + comes from the environment returned by (environment ...). In the latter case, + has to be looked up first.

@Zambito1
Copy link
Author

Zambito1 commented Mar 14, 2023

Hi Marc,

"It is an error" if the first argument to eval is not a Scheme datum value.

Where is this stated? This is what I can find on eval from R7RS:

(eval expr-or-def environment-specifier)
eval library procedure
If expr-or-def is an expression, it is evaluated in the speci-
fied environment and its values are returned. If it is a defi-
nition, the specified identifier(s) are defined in the specified
environment, provided the environment is not immutable.
Implementations may extend eval to allow other objects.

Is a value (such as the value referred to by + or display in the original issue) not considered an "expression"? Of course it is not a symbolic expression where the symbols need to be looked up in the environment. But to me it seems like any atomic value should evaluate to itself. Even if this does fall under "Implementations may extend eval to allow other objects", it seems like the following should be considered valid without warning by Chibi:

(eval (list + 1 2) (environment))

To match the following existing behavior which evaluates without warning in Chibi:

(eval 1 (environment))
(let ((x 1)) (eval (list '+ x 2) (environment '(scheme base))))
((eval + (environment)) 1 2)

Edit: Another interesting example without warning:

;; even? used as a procedure from the current lexical environment, but not in an application position
(eval (list 'filter even? '(list 1 2 3 4)) (environment '(only (scheme base) list) '(srfi 1)))

@mnieper
Copy link
Collaborator

mnieper commented Mar 14, 2023

Hi Marc,

"It is an error" if the first argument to eval is not a Scheme datum value.

Where is this stated? This is what I can find on eval from R7RS:

(eval expr-or-def environment-specifier)
eval library procedure
If expr-or-def is an expression, it is evaluated in the speci-
fied environment and its values are returned. If it is a defi-
nition, the specified identifier(s) are defined in the specified
environment, provided the environment is not immutable.
Implementations may extend eval to allow other objects.

R6RS, which you may want to look up, is more precise. But what is meant here is that expr-or-def represents (as a Scheme value) an expression (or definition) as described in chapters 4 and 5 of R7RS.

Expressions (and definitions) are represented by Scheme datum values because this is what the Scheme (code) reader produces.

Is a value (such as the value referred to by + or display in the original issue) not considered an "expression"? Of course it is not a symbolic expression where the symbols need to be looked up in the environment. But to me it seems like any atomic value should evaluate to itself.

It is not an expression as defined by R7RS. Please also take a look at 4.1.2 about literal expressions.

Even if this does fall under "Implementations may extend eval to allow other objects", it seems like the following should be considered valid without warning by Chibi:

Yes, it does fall under "implementation-specific extensions". A warning is not necessarily bad because it can help write portable programs.

(eval (list + 1 2) (environment))

To match the following existing behavior which evaluates without warning in Chibi:

(eval 1 (environment))
(let ((x 1)) (eval (list '+ x 2) (environment '(scheme base))))
((eval + (environment)) 1 2)

The first two expressions are standard R7RS. Chibi is inconsequential by not issuing a warning for the last expression. This is due to how literal expressions are implemented.

The same issue shows up in the "another interesting" example.

@mnieper
Copy link
Collaborator

mnieper commented Mar 14, 2023

PS If you need to "inject" values into an expression to be evaluated in a portable way, you can use the following idiom:

((eval '(lambda (plus) (plus 1 2)) (environment '(scheme base))) +)

@Zambito1
Copy link
Author

I think I understand better now :) the duality between literal expressions and their symbolic values made it seem inconsistent to me.

I also just made this macro based on that pattern:

(define-syntax eval-with
  (syntax-rules ()
    ((_ (injections ...) expr env)
     ((eval `(lambda (injections ...) ,expr) env) injections ...))))

(eval-with (+) '(+ 1 2) (environment '(only (scheme base) lambda))) ; => 3, without warning

Thank you for helping me understand!

@mnieper
Copy link
Collaborator

mnieper commented Mar 14, 2023

This macro is a clever idea!

@Zambito1 Zambito1 closed this as completed Feb 6, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants