Pergunta

I want to create the equivalent of a "nested LET" as in Haskell, where I can refer to some values bound in the outer LET. The caveat is that the function defined in the inner scope needs to dispatch on the type of its argument, so defgeneric came to mind.

Now this is my confusion: I have only ever defined this at "top level" (at package scope); is it possible to define it within an arbitrary lexical context ?

If not, is there a recommended alternative ? One hacky solution would be to pass the "context" as a defstruct argument to the function, I'm hoping there's something better ?

(I hope my intent is not lost in translation!)

Edit: This was a stupid question, I should have just tried it. In case someone looks for the answer to this, it is YES, and also "of course", (duh)

As a simple example,

(let ((x 4))  
      (defgeneric bar (y))  
      (defmethod bar ((y integer)) (1+ y))  
      (bar x))

evaluates to

5
Foi útil?

Solução

You can do that. It has a few downsides.

  • DEFMETHOD and DEFGENERIC are top-level forms. This means that the file compiler recognizes them and then knows about them. Inside a LET, these forms are no longer top-level forms and the compiler does not recognize them.

  • It makes debugging harder. Suddenly there is a context for methods.

  • It makes updating methods harder. I can't not just evaluate a DEFMETHOD form to update the method, I would also need to evaluate the context.

There are two typical ways to use a context at runtime:

  1. Use a dynamic binding at runtime
  2. Use a parameter at runtime

Example for 1:

(let ((*user* (find-current-user)))
  (declare (special *user*))
  (serve-page ...))

Alternatively the special variable could be declared global.

Example for 2:

(serve-page ... :user (find-current-user))

Even a plain package local variable can be good enough...

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top