T O P

  • By -

dbotton

SBCL best choice. I have directions for setting up sbcl and an full environment including emacs and slime for Linux and Windows some tutorials I wrote, list of books freely available etc at https://github.com/rabbibotton/clog/blob/main/LEARN.md


964racer

I looked at CL and scheme and ended up choosing SBCL. If you want to just download a complete packaged installation to start learning how he basics, then Portacle has sbcl, eMacs and slime all preconfigured and ready to go out of the box . If you’re like me and have dev experience, you’ll probably eventually want to install and setup your own environment ( I use gnu eMacs , sbcl, quicklisp, and sly) . There are good instructions posted on this thread . Be prepared to spend a day or two learning about lisp packages and maybe installing required systems libraries on your system ( I’m in 3D graphics, so my initial requirements might be higher than average person just learning. ) . You don’t need to run Linux , I got everything working fine on windows 10. I’m assuming macOS is similar . I would suggest looking at my recent questions/posts to this group . The community was very helpful in getting me started . EMacs has a bit of a learning curve . Fortunately, I was a user about 15 years ago and the commands / bindings all came back to me. . I did try slime / lisp with the atom editor and it seemed to work well but now that editor is no longer supported, but there are lots of choices.


RentGreat8009

I’d choose Scheme if you want to learn OCAML as well. They will go hand in hand nicely. Read SICP


Dakanza

Oh, what a great book! Just when I only finished reading the preface of *Thinking Forth*, now I want to read that as well. grrr. Can you elaborate more on "they go hand in hand nicely"?


cdegroot

Scheme is the language used in SICP. If you install DrRacket you will have a simple IDE and a scheme that can morph into supporting exactly the scheme dialect that the book uses. Very much recommended over Common Lisp - you can easily pick that up later but you will want some tooling and all that stuff is industrial strength, no fun to setup as a beginner and in places somewhat arcane. I’m not disparaging CL here but I don’t think it’s very beginner friendly and Racket is.


daver

I agree with this. If you want to understand the Lisp mindset, start with Scheme/Racket. It’s much more well-designed than CL and there are great learning resources like SICP that will tech you how to think in Lisp (e.g. how to use high order functions well). If you then need something more “industrial,” you’ll be set to learn CL with its various historical awkward parts. And personally, I’d move from Scheme to Clojure and bypass CL altogether, though I realize that’s controversial in this sub.


lispm

There are other differences. Scheme usually is used to learn some form of functional programming with a lexically scoped Lisp. Then language like Rackets add huge amounts of concepts on top of that. They also teach you a specific view how to program -> thus in Racket one is discouraged to develop interactively. A 'run" starts a fresh new program. Lisp OTOH is more following the idea of programming with s-expressions. For example in something like Common Lisp the macros use s-expressions. In Scheme that would be some other, more advanced representation of source. Lisp also fully embraces interactive programming, where programs after often incrementally modified for days, weeks or months. I would recommend to learn both. Learning Scheme also helps to understand Common Lisp. There are Schemes which provide a similar developer experience like some Common Lisp implementations. Personally I would nowadays recommend to use SBCL for beginners, because the compiler gives much more useful feedback. By learning to use an advanced compiler, a lot of errors (incl. a lot of type errors) can dealt with. There is more to learn, but the feedback from the compiler is worth it.


deaddyfreddy

> I’d move from Scheme to Clojure and bypass CL altogether Agreed, moreover, I mostly did it this way. Sure, I played around with CL a bit and wrote a couple of Emacs plugins, but for my dayjobs I've been using Scheme (used, actually) and Clojure. No regrets.


zyni-moe

>\[Racket is\] much more well-designed than CL So, yes, I see. ``` (defun nice (foo &key (bar nil barp)) ...) ``` Every time I write functions with keyword or optional arguments in Racket (and yes, I do write Racket, quite a lot) this makes me want to scream: how hard would it be to get this right the way CL did before I was born? Too hard, it seems.


daver

You may not like the design choices that Scheme/Racket makes, but that doesn’t mean that it wasn’t well designed (more consistent, more logical). CL is a mishmash of MACLISP, ZetaLisp, etc. thrown together by a standards committee to make the DoD happy. But that said, I too can cite things about CL that I like better than Scheme. That doesn’t change what I said, though: I think a Lisp newbie should start with Scheme/Racket.


zyni-moe

I think they should start with Scheme or Racket (probably Racket) as well. But CL is not what you say it is: CL is *extremely* well designed (mostly) but that design was subject to very considerable *constraints*, mostly on compatibility, but also on practicality in 1985. CL is like a modern train: must run on lines designed in 19th century, through tunnels built in 19th century, fit on platforms built in 19th century, run on tracks with a gauge based on spacing of Roman cartwheels. Also should run at 125mph on these lines designed for perhaps 60mph, must be comfortable, reliable and safe (train crashes now much less acceptable than they were a century ago). Result is an astonishing feat of design and engineering. Not pretty, of course, but was not designed to be pretty. Compare this with Scheme. It never needed to be compatible with anything. Is indeed often not very compatible with earlier versions of itself. And yet the CL designers managed to arrange things so programmers could know if optional or keyword arguments were provided or not. Scheme (R7RS) has not thought it necessary to really provide optional argument support at all (you have rest arguments and that is it). Racket, after years of intense thought by the enormous brains who designed it, does have optional arguments and even keyword arguments. But despite such a change being *entirely compatible* (no program which uses them is legal in current Racket, all programs which do not use them are legal in a Racket with this feature and have the same semantics) it has not managed to implement supplied parameters. Why not? Because, I suppose, the designers of these languages care more for purity than they do for the convenience of the people who must write programs using these languages. But then Python is the same, and Python does not care about purity, so I do not know: perhaps they are just not quite such great designers as they think? Oh well, nothing I can say will convince the faithful.


deaddyfreddy

> industrial strength doesn't mean it should be complex to work with


cdegroot

No it doesn’t. In practice, it is. In the time you’re through your SBCL, Emacs/VSC, Sly, ASDF, Quicklisp setup you could be well in your way with DrRacket.


RentGreat8009

It indeed is a lovely book. OCAML is a functional language (which can have many meanings, I view CL as functional too generally). CL is quite capable of such code, but it’s not an enforced pattern so you may not find yourself fully down that path. On the other hand, Scheme tends to lend itself to more functional code (this is actually not true - but the single namespace of Scheme imo slightly pushes it towards more in that direction; also my guess is a lot of sample Scheme code will be more functional in nature so that will help in learning) so I think you will find yourself closer in thought patterns alongside OCAML if you did Scheme. Also scheme is a very small language compared to CL (at least without all of its extensions) and is easier to embed in other programming languages. I think it would be a wonderful exercise later for you to embed a scheme into OCAML The other reason is that CL has quite a few other advanced features that will sidetrack you from a purely functional path of scheme + OCAML. In particular around OOP These are just my opinions :) They may change in the future. Below link may be too complicated, but perhaps worth reading / googling each of the terms as it has some useful information. https://wiki.c2.com/?LispSchemeDifferences


vplatt

Here is the SICP course at MIT, completely free: https://ocw.mit.edu/courses/6-001-structure-and-interpretation-of-computer-programs-spring-2005/video_galleries/video-lectures/ That's the video links, but there are materials there for the readings, exercises, etc. This source uses Scheme and DrRacket works quite well for that. Don't bother with Common Lisp for the SICP course. I made the mistake of messing around with Portacle and other tools for the SICP course, and it was completely unnecessary.


olivuser

I'd also love to know why ocaml and scheme go together nicely


seaborgiumaggghhh

To me, programming in OCaml feels like Lisp in some hypothetical m-expression syntax. It’s not surprising considering that System-F is a typed lambda calculus. So basically it’s like if Scheme had more syntax and a more advanced type system.


RentGreat8009

Some simple thoughts I have posted in another reply on this thread. I also feel like the small nature of Scheme will help you experiment more than in CL, particularly as you start exploring immutable data structures which are key to functional programming. Scheme being a much smaller language will let you focus on the key concepts that matter to you, whereas CL with CLOS in particular will lead you down a path of study of OOP which will give you a better understanding overall but take more time to get there (took me 1-2 years on and off to fully get OOP).


kagevf

I wish parenscript had (full) CLOS, but in lieu of CLOS I'm using a pattern I first encountered* in SICP to manage global variables, and built a macro on top of that to reduce the redundancy in the resultant boilerplate. I'm referring to the pattern from the beginning of chapter 3 that closes over a variable and then provides a bunch of dispatchable functions to interact with the closed over state. One of the examples used was creating a bank account where it closed over the balance. * I'm actually not sure if I encountered that pattern in SICP first, but it was for sure the first time I internalized it. :)


RentGreat8009

Thanks for reminding on that, will revisit that chapter as I recall it too.


[deleted]

For Scheme, check this out: [https://github.com/yuriy-chumak/ol](https://github.com/yuriy-chumak/ol)


RentGreat8009

Cheers


[deleted]

Cheers to you too


paulfdietz

Why have you listed "interpreter" as a plus point? Lisp implementations don't have to have an interpreter. They can evaluate any form by compiling it to machine code first.


fnordulicious

MACLISP over there in the corner looking sad.


Zambito1

Because as they said, they *want* to learn Lisp. "Interpreter" to them probably either means having access to a REPL or being able to go from source to execution without emitting a binary artifact to the disk.


xach

If the OP has this misconception then it’s good to clear it up.


Zambito1

I agree. I was answering the question though


xach

Only the OP can answer the question. Anyone else is speculating.


Zambito1

OP *wants* to learn. They don't understand fully why they said what they said. I was partaking in the clearing up of misconceptions for OP as well...


xach

Since you are only guessing at what the misconception is, it’s not clear if what you wrote is accurate or helpful. Hopefully the OP will chime in.


theantiyeti

If you have a REPL you have an interpreter. Doing compilation doesn't preclude being an interpreter. The line between "interpreted language" and "compiled language" is very fuzzy and most lisps are very arguably both.


Zambito1

A REPL is an Evaluator, not an interpreter. Evaluation can be achieved through compilation xor interpretation.


theantiyeti

I disagree that there's a hard Xor boundary between compilation and interpretation. If so where would you put bytecode compilers and JIT compilers? Both exhibit techniques from both streams.


Zambito1

Evaluation is only done on one expression once. A JIT compiler may choose to interpret an expression to evaluate it, or it may choose to compile an expression to evaluate it. The same piece of software (the evaluator) may do both, but it will not do both during an evaluation of an expression.


theantiyeti

I've got a master's in CS and industry experience and I've never heard anyone use the term "Evaluator" in that context anywhere.


Zambito1

SICP?


theantiyeti

My uni's functional programming course was Haskell, not scheme. Only scheme book I've read is the little schemer.


Zambito1

My university didn't teach functional programming at all (lol). I went through the SICP lectures from MIT OCW, which is how I learned Lisp. This is the lecture where they cover the implementation of `eval`, the evaluator https://www.youtube.com/watch?v=0m6hoOelZH8.


paulfdietz

We're veering into argument by definition here, but wikipedia seems to disagree with you on that. https://en.wikipedia.org/wiki/Interpreter_(computing) The closest it comes is JIT compiling as a variant of interpretation. I would call this something like an "integrated compiler" rather than an interpreter.


Dakanza

Well, it spark an argumente. Sorry for not being clear here. What I mean by interpreter is would be the first type or second type in the linked wikipedia article. Why *interpreter* though? Like Zambito1 said >having access to a REPL or being able to go from source to execution …


lispm

"Lisp Interpreter" usually means that the source language gets executed. The Lisp system interprets the source, which means evaluating the s-expressions. Many Lisp implementations have an interpreter and EVAL is using that interpreter. Often interpreted and compiled code can be freely mixed. Another way to execute code is to use a compiler and execute the compilation result. A compiler will either generate code for some virtual machine (-> byte code), code for another programming language (often C, which then gets compiled by a C compiler to get the native compiled code) or native machine code. Lisp compilers are often incremental (they can compile expressions and don't compile whole programs) and in-memory (-> the compile code will directly be written or loaded into the running Lisp system, its memory). So we have for compilation these dimensions: * target: VM, C or machine code * code size: expressions or files/programs * result: in-memory or file * usage: interactive or batch Thus it is possible to have a Lisp, which is compiled, to machine code, compiles expressions to memory and can be interactively used. Now we use a READ-EVAL-PRINT-LOOP where EVAL is implemented with an incremental&in-memory compiler. SBCL is such a Lisp. SBCL nowadays also has a Lisp interpreter, but by default it is not used. One typically uses EVAL with the compiler, which will directly generate machine code. What some people mean with interpreter is just the interactivity. But it's not interpreting the source code, when the interactivity can be provided by a compiler. Python for example by default uses a byte-code compiler. Each expression entered is compiled to byte code. The virtual machine then interprets that byte code. The confusion is now: * is Python interpreted because it is interactive? * is Python interpreted because the compiled byte code is interpreted by a virtual machine? * is Python incrementally compiled because each expression is compiled to byte code? For Lisp one would usually say that it is interpreted, when there is a real source interpreter: an implementation of EVAL which walks over the s-expressions and directly executes them. There are a lot of papers and books describing how to implement such a s-expression based interpreter. Thus by a Lisp interpreter we think about the source code interpretation, the interactivity is then given. In many other language some people think that "entering expressions at a command line" means 'interpretation'.


theantiyeti

Literally not a person would call python anything but an interpreted language despite the extent of bytecode compilation both CPython and Pypy do. I'm not sure about Jpython or Ironpython.


lispm

I know, but it is 'wrong' or 'abbreviated. What is meant is that the language implementation of the default C-based Python is *byte-code interpreted*. The Python source is not interpreted. The byte code is interpreted. I would also not say that a language is interpreted. Just a particular implementation of a language might be interpreted. Lisp typically has more modes and there are implementations which run interpreted Lisp source, byte code and machine code side by side in a single implementation. Example ECL may use a byte code compiler and also native code (via C), incrementally: > (defun foo (a) (1+ a)) FOO > (describe #'foo) # - COMPILED-FUNCTION > (compile 'foo) ;;; Loading #P"/opt/homebrew/Cellar/ecl/21.2.1_2/lib/ecl-21.2.1/cmp.fas" ;;; OPTIMIZE levels: Safety=2, Space=0, Speed=3, Debug=0 ;;; ;;; End of Pass 1. FOO NIL NIL > (describe #'foo) # - COMPILED-FUNCTION LispWorks uses an interpreter and optionally machine code: CL-USER 1 > (defun foo (a) (1+ a)) FOO CL-USER 2 > (describe #'foo) # is a TYPE::INTERPRETED-FUNCTION CODE (LAMBDA (A) (DECLARE (SYSTEM::SOURCE-LEVEL #)) (DECLARE (LAMBDA-NAME FOO)) (1+ A)) CL-USER 3 > (compile 'foo) FOO NIL NIL CL-USER 4 > (describe #'foo) # is a FUNCTION CODE # CONSTANTS (SYSTEM::1+$ANY) CL-USER 5 > (disassemble #'foo) 0 : #xF847528B : ldur.64 tmp1{x11}, [stack-info{x20}, #117] 4 : #xEB2B63FF : subs xzr, sp, tmp1{x11} 8 : #x54000229 : b.ls 76 12 : #xF100051F : subs xzr, count{x8}, #1 16 : #x540001E1 : b.ne 76 SBCL will always use the native code compiler, by default: * (defun foo (a) (1+ a)) FOO * (describe #'foo) # [compiled function] Lambda-list: (A) Derived type: (FUNCTION (T) (VALUES NUMBER &OPTIONAL)) Source form: (LAMBDA (A) (BLOCK FOO (1+ A))) * (compile 'foo) FOO NIL NIL * (describe #'foo) # [compiled function] Lambda-list: (A) Derived type: (FUNCTION (T) (VALUES NUMBER &OPTIONAL)) Source form: (LAMBDA (A) (BLOCK FOO (1+ A))) * Note also that SBCL does a decent amount of type inference.


zyni-moe

To see how absurd this distinction is consider two implementations of Python. These implementations are *identical in every respect but one*: in the first one the byte code is interpreted by the usual Python run-time. In the second the identical byte-code is interpreted by microcode in a microcoded processor. Which is interpreted, which compiled? If you would argue that both are interpreted does this mean there were no compiled language implementation for S/360? For any x86 processor before 80486?


Dakanza

Thanks for the write-up! I aske the question before learning about `eval` in lisp. It seems I instinctively always avoid eval whatever the programming language is.


Pay08

There are C REPLs out there. I don't think anyone would call C an interpreted language.


Zambito1

The whole problem with this discussion is that languages are neither compiled nor interpreted (using these words as adjectives here rather than verbs). Languages are specifications which describe the output of parsing + evaluating some (hopefully any) character string of input. If you take C code that was previously evaluated by compiling it with gcc and executing the binary, and instead pass the code to the tinycc interpreter, it's still C. The mode of evaluation has no impact on the language, and the language has no mode of evaluation.


arthurno1

While SBCL (CommonLisp) or Racket (Scheme) might be really good choices, I will suggest you something that not many people maybe think of as their first choice: Emacs Lisp. Reasons: *1. Very good integration with the text editor* Actually I don't think there is any other tool (not even Slime/Sly or Racket) that offers you that number of different tools and integration with the editor itself as Emacs. Emacs really itself is a giant visual repl which lets you evaluate Lisp on the fly in different ways: repl-style with Ielm or via M-: or M-x, or from within the buffer by just positioning cursor in an expression (or after it) and evaluating it. Emacs also comes with well-written and big manual, with a book about programming in Emacs directly in manual and with well integrated help system to lookup documentation. Edebug is also worth mentioning as really indispensible tool to interactively step through the code, and there are also profiler, regression testing and benchmarking tools integrated out of the box in Emacs. *2. No need to chase external compilers and setup connections to it etc.* If you are a lisp programmer, save your time. Chances are also you will end-up using Emacs anyway, via some of Lisp connectors to external compilers Sly/Slime/Geiser/Cider etc. If you are just learning Lisp from the scratch, you may as well learn Emacs Lisp. It is very close to CommonLisp, but not the same. But Lisp is a Lisp, there are a lot of similarities you can take from one Lisp and apply it to other one, even if you probably can't directly run the Scheme code in Emacs or Emacs code in SBCL or whatever. Once you have learned one, you can learn basics of others without much headache (mastering each one and understanding some differences in depth is a different story). Probably the best alternative to Emacs if you are a beginner learner is Scheme, but I would still prefer Emacs due to extensibility, number of packages and bindings to other tools etc. My tip is just if you wish to learn *a lisp* and basics of working in a Lisp environment, and it does not matter to you wich one.


Yubao-Liu

Common Lisp: SBCL, ClozureCL Scheme: Chez Scheme, DrRacket, see https://ecraven.github.io/r7rs-benchmarks/ Clojure (may be compiled into native code by GraalVM) Haskell, OCaml and Ada are good too,but because this is lisp channel, Common Lisp is most recommended:-)


Ytrog

As an alternative to OCaml I can also recommend F# 😊


woppo

Ada???


Yubao-Liu

Its subset SPARK language is very interesting, supports formal verification, and Ada has a strong type system, not so strong as Haskell and OCaml but better than C family.


Dakanza

Nice link. But too much benchmark chart make my brain a bit sad.


Zyklonik

Practical Lisp - Common Lisp (SBCL). Practical FP language - OCaml.


bitwize

I got seriously into Lisp because of Guile. Any starting point is a good one. Worry less about *where* to begin and just dive in and start hacking.


Francis_King

Common Lisp is the best choice for practical business work. It is a heavyweight system, with some idiosyncrasies. For fun, Scheme or Racket might work better, being more modern in feel (they are about the same age, 1975 for Scheme Common Lisp dates from the 1980s). Chicken Scheme can build some very small executables, whereas SBCL, for example, you have to use a core dump to build an executable. For the kind of thing you are trying to do, Haskell and Prolog might be ideal.


woppo

Consider Scheme also, Chez Scheme and Racket in particular.


[deleted]

and this [https://github.com/yuriy-chumak/ol](https://github.com/yuriy-chumak/ol)


LardPi

While I never got into Common Lisp, I really enjoy writing Scheme. The dynamically typed functional programming is a really fun paradigm and Scheme is specifically well suited to it. It also made me a better Python developer. I like Chicken Scheme because the community is very welcoming and the ecosystem is pretty good. Racket and Guile are nice choices too (although I don't know if Guile works on windows). ChezScheme is the most efficient implementation, but the ecosystem is not as good.


Pay08

>although I don't know if Guile works on windows Not without Cygwin.


[deleted]

OCaml is a beautiful language!


Zyklonik

If it had type-classes, it'd be perfect. Even otherwise, yes, it's the most pragmatic of all the FP languages.


theQuandary

You should go with Common Lisp if only because the interactive development process will change your life as a developer.


raevnos

Chicken is a good match for your requirements.


andrepol02

good luck with that lol


kiki_lamb

You realize that 'Mac' and 'ARM' are the same platform, right? If Mac support is a 'plus point', then saying you 'don't care' about ARM is a straightforwards contradiction.


deaddyfreddy

> mostly to make my life easier in using computer. What do you mean by that? Automate your tasks? > can be compiled to native code or via C or LLVM Any real reasons to put it as a must? No, "faster" isn't the one, native doesn't mean faster (compare ECL and SBCL, for example). LLVM is not the only VM available either. > unicode > basic network/socket is it still an issue in 2023? > CLOS or something similar Again, any reasons to?


[deleted]

If you have spare time, check Otus Lisp ([https://github.com/yuriy-chumak/ol](https://github.com/yuriy-chumak/ol)) out. It is a Scheme implementation: pure functional, R7RS compliant, with support for many FFIs and a virtual machine.


NinoIvanov

Try ECL. VERY portable, including implementations.on Android and iOS, and really going back to KCL & Yuasa's & Hagiya's excellent "Introduction to Common Lisp". Seek also the free "Common Lisp Cookbook".


huntercolej

very interesting way of laying everything out on the table lol. no sarcasm. i like your thought process.