Scheme newbie question-
Is there a way for me to reset my current REPL environment (i.e. the default user environment) without quitting and restarting my REPL? Basically I'd like a way to wipe out my current environment so that none of my previous defines are in effect. This is using GNU/MIT Scheme.
If this is impossible, what's the best practice here when just messing around with code in the REPL? I've heard people talk about creating and deleting packages, but most examples seem to be for Common Lisp which is a bit different.
I did find information on how to do this in the Clojure REPL but there were caveats and it seems like it's Clojure-specific: Can I clean the repl?
Thanks!
Edit: I'm able to accomplish functionally the same thing by quitting and restarting the REPL process itself. I found a way to do this but keep the connection to my editor (vim) alive using vim-screen. This is an acceptable solution if there's no way to do it from within the REPL. However, I'll keep the question open a bit longer to see if there's a way to do this inside the language as I think it will be instructive.
I think that this is implementation specific, but in MIT Scheme you can clear the REPL environment with:
1 ]=> (ge (make-top-level-environment))
The function (ge [environment]) "Changes the current REP loop environment to [environment]." and the function make-top-level-environment "returns a newly allocated top-level environment".
MIT Scheme has a bunch of environment-management functions that you can peruse here
I tested this on Mac OS X (10.6.7) with MIT Scheme 9.0.1 installed via the pre-built binary from the GNU site, with the following REPL session:
1 ]=> (define foo 1)
;Value: foo
1 ]=> foo
;Value: 1
1 ]=> (ge (make-top-level-environment))
;Value 13: #[environment 13]
1 ]=> foo
;Unbound variable: foo
;To continue, call RESTART with an option number:
; (RESTART 3) => Specify a value to use instead of foo.
; (RESTART 2) => Define foo to a given value.
; (RESTART 1) => Return to read-eval-print level 1.
2 error>
I think that different implementations have different conventions but I don't think there's anything quite like Common Lisp's packages. If you're not wedded to MIT Scheme, you should check out Racket and Dr Racket, which is a nice IDE that might be more powerful than a plain REPL at the command line, and I think it has some kind of module system. Racket is its own dialect of Scheme, so depending on what you're doing, it might not be appropriate. (the default language module in Racket is not the same as MIT Scheme)
I've struggled with all this recently (past few months) when I went looking for a Scheme that could run the code from Lisp in Small Pieces, which has a bunch of weird macros. Gambit ended up being the best bet. If you don't have a need like this though, check out Racket.
Related
I am interested in creating an emacs extension that delegates the work to an external program.
I have my logic as a library, however, written in Common Lisp. If I can directly call the CL library from Elisp, that would be simpler for me; otherwise, I can use a client/server architecture.
I have looked into emacs LSP implementation, but I couldn't find a simple entry on how to do it.
You could build a binary of your CL app and call it from the Elisp side. It seems to suit you fine, so here are more pointers:
How to build a Common Lisp executable
short answer: see https://lispcookbook.github.io/cl-cookbook/scripting.html
Building a binary is done by calling sb-ext:save-lisp-and-die from the terminal (and not from a running image). Note that this function name changes on the different implementations.
ASDF has a directive that allows to do it declaratively, and portably (for all implementations). You add 3 lines in your .asd file and you mention what is your program's entry point. For example:
;; myprogram.asd
:build-operation "program-op" ;; leave this as is.
:build-pathname "myprogram"
:entry-point "myprogram::main" ;; up to you to write main.
Now, call (asdf:make :myprogram).
See a more complete example in the Cookboo.
Call it from Elisp
See https://wikemacs.org/wiki/Emacs_Lisp_Cookbook#Processes
This returns the output as a string:
(shell-command-to-string "seq 8 12 | sort")
Full documentation: https://www.gnu.org/software/emacs/manual/html_node/elisp/Synchronous-Processes.html
Other approaches
Other approaches are discussed here: https://www.reddit.com/r/lisp/comments/kce20l/what_is_the_best_way_to_call_common_lisp_inside/
For example, one could start a lisp process with Slime and execute CL code with slime-eval.
In a CppCon talk (https://www.youtube.com/watch?v=80BZxujhY38 at 5:00)
Herb Sutter alluded to defun defun 3 being somehow a problem. After
I googled it, it's still not clear to me why. Can someone elaborate?
In a comment from the same video:
Herb Sutter
See also the paper, P0707 (http://wg21.link/p0707), and search for "defun." Lisp defun (and Scheme define) lets you define a function... but in Lisp and Scheme you can even redefine built-in functions and macros, including defun/define itself which is what "defun defun" / "define define" does. Here's a sample related StackExchange question: https://emacs.stackexchange.com/questions/375/symbols-value-as-a-variable-is-void-defun-when-reloading-emacs .
I'm not interested in doing anything like that in C++, and there's nothing like that in my proposal, you can't change any definitions (including of this class after it is defined), you can't reach out and affect anyone else's type or code, the only thing you can do is participate in generating the one-time-and-then-immutable definition of this class you're writing right now which is nice and localized and bounded... and still very powerful.
The linked paper contains this section:
5.2.1 Problems in other languages
In Lisp and related languages, programmers can redefine other people’s code and even global language facilities (e.g., the notorious (defun defun () 3) in Lisp, or (define define () 3) in Scheme). This is powerful, but undisciplined (causes arbitrary global effects up to and including breaking the language itself), fragile (Lisp makes it notoriously easy to write “write-only” code that is difficult to review, read, and maintain), and causes programs to be tightly coupled among their components and with their developer’s environment (Lisp makes it notoriously easy to write code whose meaning depends on local customizations, is hard to share, and when shared is hard to compose with other code that came from an environment with competing assumptions).4
The footnote says:
4 Various incarnations and offshoots of Lisp attempted to mitigate this problem in various ways without actually taking away the root cause: Common Lisp added the guarantee that all symbols in the package COMMON-LISP are protected and must not be redefined by user code otherwise you get undefined behavior; although this provides some protection for the standard facilities, it does not solve the general problem because it still permits one set of user code to redefine things in another set of user code. Also, implementations like SBCL attempted to further improve the problem by providing ways to “lock” packages so their contents cannot be accidentally redefined; however, even SBCL also provides ways to “unlock” them again.
The Racket docs indicate that Racket has separate forms for: require, load, include, and import. Many other languages only contain one of these and are generally used synonymously (although obviously with language specific differences such as #include in C, and import in Java).
Since Racket has all four of these, what is the difference between each one and which should I be using in general? Also if each has a specific use, when should I use an alternative type? Also, this question seems to indicate that require (paired with provide) is preferred, why?
1. Require
You are correct, the default one you want is almost always require (paired with a provide). These two forms go hand in hand with Racket's modules and allows you to more easily determine what variables should be scoped in which files. For example, the following file defines three variables, but only exports 2.
#lang racket ; a.rkt
(provide b c)
(define a 1)
(define b 2)
(define c 3)
As per the Racket style guide, the provide should ideally be the first form in your file after the #lang so that you can easily tell what a module provides. There are a few cases where this isn't possible, but you probably won't encounter those until you start making your own Racket libraries you intend for public distribution. Personally, I still put a file's require before its provide, but I do sometimes get flack for it.
In a repl, or another module, you can now require this file and see the variables it provides.
Welcome to Racket v6.12.
> (require "a.rkt")
> c
3
> b
2
> a
; a: undefined;
; cannot reference undefined identifier
; [,bt for context]
There are ways to get around this, but this serves as a way for a module to communicate what its explicit exports are.
2. Load
This is a more dynamic variant of require. In general you should not use it, and instead use dynamic-require when you need to load a module dynamically. In this case, load is effectively a primitive that require uses behind the scenes. If you are explicitly looking to emulate the top level however (which, to be clear, you almost never do), then load is a fine option. Although in those rare cases, I would still direct you to the racket/load language. Which interacts exactly as if each form was entered into the repl directly.
#lang racket/load
(define x 5)
(displayln x) ; => prints 5
(define x 6)
(displayln x) ; => prints 6
3. Include
Include is similar to #include in C. There are even fewer cases where you should use it. The include form grabs the s-expression syntax of the given path, and puts it directly in the file where the include form was. At first, this can appear as a nice solution to allow you to split up a single module into multiple files, or to have a module 'piece' you want to put in multiple files. There are however better ways to do both of those things without using include, that also don't come with the confusing side effects you get with include.1 One thing to remember if you still insist on using import, is that the file you are importing probably shouldn't have a #lang line unless you are explicitly wanting to embed a submodule. (In which case you will also need to have a require form in addition to the include).
4. Import
Finally, import is not actually a core part of Racket, but is part of its unit system. Units are similar in some ways to modules, but allow for circular dependencies (unit A can depend on Unit B while Unit B depends on Unit A). They have fallen out of favor in recent years due to the syntactic overhead they have.
Also unlike the other forms import (and additionally export), take signatures, and relies on an external linker to decide which actual units should get linked together. Units are themselves a complex topic and deserve their own question on how to create and link them.
Conclusion (tldr)
TLDR; Use require and provide. They are the best supported and easiest to understand. The other forms do have their uses, but should be thought of 'advanced uses' only.
1These side effects are the same as you would expect for #include in C. Such as order being important, and also with expressions getting intermixed in very unpredictable ways.
I'm an experienced C++/.NET/Java Windows/web programmer trying to learn (Common) Lisp. I'm reading Practical Common Lisp and using SLIME.
I'm getting the Lisp language easily enough, but I'm having trouble groking the mechanics of development. One of my issues is dealing with Emacs. I have no experience with it and find it generally confusing with hard to find/figure out commands.
Specific questions:
I get the REPL, but I don't quite get how I can use it effectively. When I need to change a function I have to retype the defun and make changes (tedious and error prone). How can I do this better?
How do I get from entering code at the REPL to actually having a program? I'm used to the C model where you have code files that you can review, edit and recompile. I know Lisp has something similar (via the load function), but how does one get a function I just defined and tested into a file to be saved? I'm hoping there's a better method than my current select+copy+paste.
How do you debug errors? Is there any ability to step into code like I would with other languages?
As long as the S-expression is valid, I don't get any errors when entering a (defun ...). It's not until I try to use it that I find out it's not valid. Is there any way to get errors sooner (i.e. compile the code)?
Is there some IDE that would be more familiar to me or allow me to play with the language easier?
Should I switch to learning Scheme instead?
Any tips would be greatly appreciated!
-I get the REPL, but don't quite get how I can use it effectively. When I
need to change a function I have to
retype the defun and make changes
(tedious and error prone). How can I
do this better?
-How do I get from entering code at the REPL to actually having a program?
I'm used to the C model where you have
code files that you can review, edit
and recompile. I know lisp has
something similar (via the load
function), but how does one get a
function I just defined and tested
into a file to be saved? I'm hoping
there's a better method than my
current select+copy+paste.
Load SLIME. Enter code in your .lisp file, and then run slime-eval-buffer to load all your code into Lisp. Then, for a specific function you are hacking on C-e, C-j to redefine it in your running Lisp.
-How do you debug errors? Is there any ability to step into code like I would with other languages?
Yes. (trace 'my-function) - or some variant on that - and when my-function is called, it will break into the debugger.
-As long as the S-expression is valid, I don't get any errors when entering a
(defun ...). It's not until I try to
use it that I find out it's not valid.
Is there any way to get errors sooner
(i.e. compile the code)?
To some degree, that is a characteristic of dynamic languages (Python, Perl, Ruby, Lisp, etc.). Try SBCL for better error-checking.
-Is there some IDE that would be more familiar to me or allow me to play with the language easier?
Emacs is the free IDE for Lisp. Allegro has a free edition I believe; I've never tried it though..
-Should I switch to learning Scheme instead?
Nah, Scheme is not as pragmatic a language.
I'm an experienced C++/.NET/Java Windows/Web programmer trying to learn (Common) Lisp. I'm reading Practical Common Lisp and using SLIME.
One can also use the LispWorks Personal Edition for learning Lisp. It has some limitations and the full product is commercial, but it is quite a bit easier to use.
I get the REPL, but don't quite get how I can use it effectively. When I need to change a function I have to retype the defun and make changes (tedious and error prone). How can I do this better?
The REPL has a history. With keyboard commands you can get back prior input and change it. Other than that just edit a Lisp file and compile code from there. In Lisp you can compile/eval individual expressions and definitions. Typical IDEs like SLIME, LispWorks or Allegro CL allow you to run code also from normal Lisp text windows - additionally to executing expressions in the REPLA (aka Listener).
How do I get from entering code at the REPL to actually having a program? I'm used to the C model where you have code files that you can review, edit and recompile. I know Lisp has something similar (via the load function), but how does one get a function I just defined and tested into a file to be saved? I'm hoping there's a better method than my current select+copy+paste.
Copy and paste in one thing. But the correct way is to work from a text file in an editor window. One can compile/load expressions, the editor buffer or the associated file.
How do you debug errors? Is there any ability to step into code like I would with other languages?
See STEP, TRACE and related. SLIME, LispWorks and Allegro CL have lots of additional features.
As long as the S-expression is valid, I don't get any errors when entering a (defun ...). It's not until I try to use it that I find out it's not valid. Is there any way to get errors sooner (i.e. compile the code)?
For many cases one uses a compiler. The compiler will find a range of errors and also will note when something is unusual (for example a function does not exist or a variable has not been defined).
-Is there some IDE that would be more familiar to me or allow me to play with the language easier?
LispWorks, Allegro CL are the best under Windows. There are some alternatives like Corman Lisp (I don't know it is maintained right now) or even Ufasoft Lisp.
Should I switch to learning Scheme instead?
Not really.
It doesn't sound like you're really using SLIME, or at least not in the way it was intended to be used. ("have to retype the defun", "the C model where you have code files")
I recommend watching some SLIME screencasts (or, even better, watching a Lisp programmer use SLIME for a few minutes, if you have one handy). The SLIME webpage has a couple.
It sounds like you'd really enjoy the DrRacket IDE. Racket is closer to Scheme than to Common Lisp, but you could dip your toes into the Lisp family without the speed bump of the Emacs style of development.
My problem isn't with the built-in eval procedure but how to create a simplistic version of it. Just for starters I would like to be able to take this in '(+ 1 2) and have it evaluate the expression + where the quote usually takes off the evaluation.
I have been thinking about this and found a couple things that might be useful:
Unquote: ,
(quasiquote)
(apply)
My main problem is regaining the value of + as a procedure and not a symbol. Once I get that I think I should just be able to use it with the other contents of the list.
Any tips or guidance would be much appreciated.
Firstly, if you're doing what you're doing, you can't go wrong reading at least the first chapter of the Metalinguistic Abstraction section of Structure and Interpretation of Computer Programs.
Now for a few suggestions from myself.
The usual thing to do with a symbol for a Scheme (or, indeed, any Lisp) interpreter is to look it up in some sort of "environment". If you're going to write your own eval, you will likely want to provide your own environment structures to go with it. The one thing for which you could fall back to the Scheme system you're building your eval on top of is the initial environment containing bindings for things like +, cons etc.; this can't be achieved in a 100% portable way, as far as I know, due to various Scheme systems providing different means of getting at the initial environment (including the-environment special form in MIT Scheme and interaction-environment in (Petite) Chez Scheme... and don't ask me why this is so), but the basic idea stays the same:
(define (my-eval form env)
(cond ((self-evaluating? form) form)
((symbol? form)
;; note the following calls PCS's built-in eval
(if (my-kind-of-env? env)
(my-lookup form env)
;; apparently we're dealing with an environment
;; from the underlying Scheme system, so fall back to that
;; (note we call the built-in eval here)
(eval form env)))
;; "applicative forms" follow
;; -- special forms, macro / function calls
...))
Note that you will certainly want to check whether the symbol names a special form (lambda and if are necessary -- or you could use cond in place of if -- but you're likely to want more and possibly allow for extentions to the basic set, i.e. macros). With the above skeleton eval, this would have to take place in what I called the "applicative form" handlers, but you could also handle this where you deal with symbols, or maybe put special form handlers first, followed by regular symbol lookup and function application.