fredokun / cl-jupyter

An enhanced interactive Shell for Common Lisp (based on the Jupyter protocol)
BSD 2-Clause "Simplified" License
199 stars 29 forks source link

Multiple forms in code cell #8

Closed mmaul closed 8 years ago

mmaul commented 8 years ago

It would be nice to have multiple forms inside a code cell without having to wrap multiple forms in a PROGN. It just adds a little extra noise. Currently when multiple forms are placed in a code cell only the first form is evaluated.

fredokun commented 8 years ago

You're right cl-jupyter is for now quite naive about evaluation... and also error reporting (notive the 'nil' when a conditions is signaled)... I think in the case of Python only the evaluation of the last form is returned... In case of multiple values (values ....) I could produce multiples Out's ? What would you think is a good behavior for common lisp ?

mmaul commented 8 years ago

Return of results of the last form makes sense which is what would happen if the forms were in a block. Values is a little trickier, often your not interested in other values but the first one, sometimes your interested in them, so I'm not sure if they would provide more value than they would noise.

One other thing, export of notebook to lisp file, can text be included as comments in the exported file. Currently it just exports the contents of the code clells

On Wed, Oct 14, 2015 at 8:36 AM, Frederic Peschanski < notifications@github.com> wrote:

You're right cl-jupyter is for now quite naive about evaluation... and also error reporting (notive the 'nil' when a conditions is signaled)... I think in the case of Python only the evaluation of the last form is returned... In case of multiple values (values ....) I could produce multiples Out's ? What would you think is a good behavior for common lisp ?

— Reply to this email directly or view it on GitHub https://github.com/fredokun/cl-jupyter/issues/8#issuecomment-148036382.

glider-gun commented 8 years ago

How about setting *, **, ***, /, //, /// like normal repl? http://www.lispworks.com/documentation/HyperSpec/Body/25_aa.htm

And maybe something like (nth 123 *out*) (nth 123 *out-values*) is nice?

mmaul commented 8 years ago

That would be good, staying as close to the repl I think would be good. Interesting I did not know about the / and + variables. And there are always nth-value and multiple-value-list for extraction of multiple values. But like I said most of the time the first values is the one of intrest so I think all this is reasonable.

On Wed, Oct 14, 2015 at 11:50 AM, glider-gun notifications@github.com wrote:

How about setting , *, ***, /, //, /// like normal repl? http://www.lispworks.com/documentation/HyperSpec/Body/25_aa.htm

And maybe something like (nth 123 out) (nth 123 out-values) is nice?

— Reply to this email directly or view it on GitHub https://github.com/fredokun/cl-jupyter/issues/8#issuecomment-148093216.

fredokun commented 8 years ago

I should have looked at the standard ... I will at least implement the stars * , ** and *** and since the Jupyter protocol makes me save some history I will probably also implement something like your *out* suggestion... But I think it's easier (from the impl. side) to define a function, something like :

(%out  <n>)   ==>  Returns Out[n]  (jupyter's view of history)
(%out <n> <m>)  ==>  Returns m-th value of  Out[n]
glider-gun commented 8 years ago

Such function looks nice, too.

fredokun commented 8 years ago

I've wrapped the code to eval in a (progn ...) form, it seems to be ok.
For the stars and %out/%in and stars I have to understand a bit more how (eval ...) works ... But please stay tuned.

fredokun commented 8 years ago

A technical comment for when I'ill be able to hack on cl-jupyter again (soon but not today)... Since eval works in the null lexical environment, I have to use special vars to inject something in the evaluator... It will work for the stars, and for the %out/%in functions I will probably also use special vars bound to lambda's to fetch the history. And in cl-jupyter-user I will put the lexical functions callable from the console or the notebook... Probably this does not make sense for anyone but me but let's say ...special vars is such a nifty feature (if this scheme works, which I do not know yet) ...

fredokun commented 8 years ago

Hi ... the idea of my previous comment indeed worked... Please see the "about cl-jupyter" document for a summary of what's available now for history management.

glider-gun commented 8 years ago

It works well! But how about

(defun cl-jupyter-user::%out (hist-ref &optional value-ref)
   (cl-jupyter::take-history-out hist-ref value-ref))

and

(defun cl-jupyter::take-history-out (hist-ref &optional value-ref)
  (let ((history-out (slot-value cl-jupyter::*evaluator* 'cl-jupyter::history-out)))
    (let ((href (if (< hist-ref 0)
                    (+ (+ (length history-out) 1) hist-ref)
                  hist-ref)))
      (when (and (>= href 1)
                 (<= href (length history-out)))
        (let ((out-values  (aref history-out (- href 1))))
          (if value-ref
              (when (and (>= value-ref 1)
                         (<= value-ref (length out-values)))
                (elt out-values (- value-ref 1)))
              (values-list out-values)))))))

so that (%out n) returns values and we can do something like below?

In [4]: (values 123 456 789)
Out[4]: 123

In [ ]: (multiple-value-bind (a b c) (%out 4)
         ...)

(I entered above definitions to cl-jypyter's notebook)

fredokun commented 8 years ago

That's better ! Could you prepare a pull request ? (If not, never mind I will make the change myself).

glider-gun commented 8 years ago

Yes, I created pull request. Is this ok?

fredokun commented 8 years ago

I've merged the pull request... It seems fine, thanks !