Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

This blog post explains the sort of workflow a Lisp/Smalltalk-style REPL enables:

https://mikelevins.github.io/posts/2020-12-18-repl-driven/



Interesting; when you define a function (or anything) in a breakloop, does it get saved to source? (or is there an option to?)

I'm trying to imagine using this style of programming in Python, but the type-redefinition problem is still there


Sometimes a break-loop is all you have.

But usually there is something around it. Typically a Lisp system can run several REPLs at the same time, one might be a break loop. You can define a function in another REPL and use it in the break-loop. You can define the function by loading code in a break-loop.

An interaction might be (here in LispWorks):

  CL-USER 6 > (> (sin-x2 3) 0)

  Error: Undefined operator SIN-X2 in form (SIN-X2 3).
    1 (continue) Try invoking SIN-X2 again.
    2 Return some values from the form (SIN-X2 3).
    3 Try invoking something other than SIN-X2 with the same arguments.
    4 Set the symbol-function of SIN-X2 to another function.
    5 Set the macro-function of SIN-X2 to another function.
    6 (abort) Return to top loop level 0.

  Type :b for backtrace or :c <option number> to proceed.
  Type :bug-form "<subject>" for a bug report template or :? for other options.

  CL-USER 7 : 1 > (load "~/sin-x2.lisp")
  ; Loading text file /Users/foo/sin-x2.lisp
  #P"/Users/foo/sin-x2.lisp"

  CL-USER 8 : 1 > :c 1
  T
A function SIN-X2 does not exist. There is an error and we get a break-loop. The break-loop is one level deep. All of Lisp is available in a break-loop: the compiler, the code loader, the evaluator, ... Lisp stays with the break-loop in the context of the error.

I define/write the function in a file and the load the file. Loading the makes the function available in the running Lisp.

Then I use the continue restart to try to find the function again -> the error is gone


In Smalltalk, the code lives inside the image. You can dump it to a file/set of files using "file-out" operation, and import it from files with file-in. But the code is never executed directly from the files - it's parsed, compiled, and executed on read, which creates runtime representation of the code which is saved in the image. When you break into a debugger in the running Smalltalk image, it works on top of the same infrastructure, giving you direct access to the actual code as well as its textual representation at all times. Smalltalk is also highly reflective, so the compiled code (methods) and objects (classes are objects) is available for introspection and modification. Though it's not the best introduction, this post may help get you interested in the paradigm: https://blog.bracha.org/exemplarDemo/exemplar2021.html?snaps...

It's impossible to do with Python, or any other language that wasn't created with image-based runtime. I tried. This approach only works when the "vertical integration" reaches from the very bottom (compilation, stack handling, memory allocation, object creation) to the very top (editing the source, refactoring, test runners, etc.) It's incredibly powerful when it works and is done right. Imagine your whole OS being built around GDB, with extremely late binding of everything and each method being a separate .so/.dll. It would probably be incredibly slow, which is why Smalltalk and Smalltalkers pioneered JITs - but it would also allow you to override any part of your running system while it's running.



My understanding is that you usually write the code in your editor and use an editor command to send the code directly to the Lisp process (that’s what I do, anyway). Or just copy-paste.

I’m not aware of a way to get code back out of the Lisp environment, but I’m fairly new to all this.


That is exactly the clarification I needed. Thanks!




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: