Lisp in Small Pieces of Clojure, part 3
gmorpheme.net
gmorpheme.net
I've recently started hacking with Elisp, and I really like it. Parenthesis are obviously pretty awkward at first. But now I wouldn't leave them for anything else. As it turns out, the brackets make it easy for your editor to understand the semantics of your code, to a whole new level. So your editor is now actively helping you navigate and edit your code. You go from expressions to expressions, add one after an other, transpose them and their parameters, absorb other expressions, insert them etc. It's true magic. I thinks that's why some don't like the fact that CL-loop is not "lispy" enough: you lose your editor's help inside a CL loop.
So the parents are actually really cool: you can basically tell your editor to move code around and insert / delete it instead of doing it yourself. With these tools (smart parents and paredit on emacs), your parenthesis are always matched ! And because it's lisp, you're actually forced to use these tools because it's a nightmare otherwise (which makes it kinda hard to learn at first), so you actually do learn them. I haven't used smartparents with other languages, but I hear it works pretty well.
Finally, it seems that lisp dialects compile to almost anything. Which means that you can use a lisp editor and get all its benefits even when working in clojure on the JVM or clojurescript on the browser etc. And once you're good at lisp, you can pretty much make Emacs do anything.
Conclusion: Lisp Is Pretty, give it a try when you get a chance ;)
[0] https://github.com/Fuco1/smartparens
EDIT: fixed some sentences so they make sense...
I still haven't actually had an occurrence when for/fold hasn't been enough for my special case needs.
It looks pretty good to me, and I hear good things about it, although frankly I've always just used LOOP.
0: http://www.lispworks.com/documentation/HyperSpec/Body/m_doti...
1: http://www.lispworks.com/documentation/HyperSpec/Body/m_doli...
2: http://www.cs.cmu.edu/Groups/AI/html/cltl/clm/node348.html#S...
A matter of preference of course. The benefits of for loops or named lets is that they are functional and thus continuation safe. I did a bunch of continuation-based nondeterminism things last year, and knowing things weren't mutating was nice.
Could any one suggest how one might do data science and analytics on Lisp?
P.S.: Hy Lang: https://github.com/hylang/hy
Considering your question, I'm not a data scientist but this book seems to come up often when search for 'lisp ai' on google. It's pretty old, but maybe it's a good place to start: https://github.com/norvig/paip-lisp
It's great for people who already use Emacs. But a lot of people have deep personal investment in other editors because they got started years ago programming in some non-lisp language for which Emacs was virtually a footnote. And sure, learning Emacs is possible for established programmers who are new to lisp, but learning a new editor in addition to a new language is a hurdle most languages don't have (or if they do, it's often a reasonably simplistic GUI IDE.) It's amazing how many books, manuals, etc start off on the first page saying something to the effect of "You don't have to use Emacs... but seriously go learn Emacs."
This all said, there are a few ways to get psuedo-SLIME behavior out of Vim but they all seem to suffer from lack of TLC and established lisp users usually look at you strange and question why you're not just using Emacs. (Also the s-exp structure of lisp code still makes it easier to manipulate in Vim (sans plugins) than other languages. The % movement really gets a workout when editing lisp code)
And it's not that you have to use Emacs to become a proficient lisper... it's just that once you're used to doing things the lisp way, you'll want a hackable environment that also does things the lisp way. This includes the editor.
That said, I prefer lisp for my smartphone programming. Not because I have emacs on my phone, but because lisp is such a great choice precisely when you don't have a good editor and keyboard.
I should say that I have no doubt my issues are of my own making. I still haven't figured out a way to run a custom non-manufacturer based AOSP ROM on my phone without weird issues.
After using it long enough, you'll realise that no editing environment even comes close. emacs really is superior to everything else out there: org-mode, magit, notmuch, gnus, slack-mode, all the different programming language modes, eshell &c. combine to form the best editing & development environment out there. From that first moment you write a little bit of elisp to make your life better and for the rest of your life (or at least as long as your eyes & hands permit you to use a computer), emacs really is worth it.
Not using emacs is a bit like trying to walk from Mexico to Canada, with one leg in a splint: possible, but why hobble yourself?
The best Lisp editing experience is only available on commercial Lisps like Allegro.
Lots of people like the auto-typing paredit intellisense style of tooling, I can't stand it personally (with the exception of megalithic Java projects where they seem like a necessary evil and both eclipse and intellij are utterly slow at it but that's another rant...), but I do appreciate vim's "%" command to jump between matching delimiters and combine that with other text editing forms, plus rainbow parens so everything is matched without having to highlight.
Anyway sometimes I wonder if a lot of newbies get turned off by the parens (in one of the various ways) then get turned off again when "use emacs with all these things!" is the only suggested way to manage that.
Also, Lisps have no static type system, and for whatever reason static type aficionados have an aversion to macros or else want to make macros typed, and combining macros with type systems again makes macros far more complicated. One need only look at Scala's many attempts at adding macros to the language to see just how hard it is, and I personally have little expectation at this point that Scala will succeed in integrating macros into the language.
At the end of the day, the major selling points of Lisps are macros, and, for Schemes, baked-in delimited continuations. Most or all other features can be found in other languages in various forms.
That's not the case. You think of s-expressions as the syntax for Lisp, while s-expression is a data syntax. Lisp syntax is defined on top of s-expressions. Think about LET. It has syntax. LAMBDA: it has syntax. And so on. Most macros implement syntax.
> Most or all other features can be found in other languages in various forms.
It's not the amount of features, it's the integration which makes the character of a language.
Now other lisps might have more forms that don't reduce quite nicely, I'm not sure, I still strongly believe in my original point that lisp practically has no syntax, and that's one of the reasons its easy to create macro systems for it.
If you actually look into the R5RS document, you can see that chapters 7.1.3-7.1.6 define the syntax for that particular toy version of Scheme.
Lisp usually has three syntax types: function applications, built-in operators and macro operators.
That you can implement some constructs by expanding them to LAMBDA expressions says nothing about the syntax of Scheme or Lisp. Lisp users don't develop in pure lambda calculus. Each built-in operator and each macro operator are adding syntax.
One can reduce arithmetic to lambda expressions - this does not mean that Scheme has no arithmetic operators. R5RS documents arithmetic and not their lambda variant. Same as R5RS defines the syntax for DEFINE, COND, IF, CASE, SYNTAX-RULES, ... That's what the progammer sees, not LAMBDA.
Take any real world Scheme, like Chicken Scheme -> lots of macros have added syntax. That's what the programmer uses, not lambda calculus.
For iteration and selection, did you just turn everything into lambdas? E.g.
(if x y z) -> (__if_fun (lambda () x) (lambda () y) (lambda () z))
If you minimize the special forms, you have fewer cases in the expanding code walker; but then the compiler has little information for producing good code.Note that a compiler doesn't necessarily just let every instance of function application be function application. If the above expansion for if is forced upon you as a compiler writer, you can recognize the __if_fun function as a built-in and open-code it, effectively undoing the reduction to function application.
Check that all arguments are lambdas (and diagnose if they aren't zero-argument lambdas) destructure them and turn into an open-coded branching construct.
The cost for fewer code walking cases in the macro expander ends up being more cruft in the compiler.
About let to lambda: in non-toy implementations, you almost always want to go the other way: recognize lambdas which can be turned into lets.
> Now other lisps might have more forms that don't reduce quite nicely, I'm not sure, I still strongly believe in my original point that lisp practically has no syntax
This isn't an argument against Lisp having syntax: it does have those operators, and each one defines its own syntax. The fact that they can be written entirely in the language itself doesn't mean Lisp doesn't have syntax, it means that Lisp has extensible syntax: you can add more syntax whenever you like, and in some dialects, you can remove or replace the pre-defined syntax forms. Syntactic sugar is still syntax, too: in C, arr[i] is just sugar for *(arr + i), but I don't know anyone who would claim that array indexing isn't part of C's syntax.
- Parinfer [https://shaunlebron.github.io/parinfer/] - makes the parens follow indentation and vice versa and effectively makes them a non-issue at worst and a great advantage at best (you can combine it with paredit later on to perform all kinds of ninja magic when editing code)
- Cursive [https://cursive-ide.com/] - a Clojure plugin for IntelliJ IDEA for a more 'just works' experience. Integrates parinfer, among other things, and is generally pretty great (I'm a happy customer).
And last but not least - rainbow parens to keep nested expressions readable. Pretty much every Lisp editor has them more or less out of the box.
Sometimes just deleting a couple of lines in Vim (IdeaVIM in my case) and knowing that parinfer will take care of the parens feels faster and more comfortable to me than using paredit. YMMV.
And as far as beginners are concerned - for someone coming from an OOP/imperative programming/C-style syntax background, a LISP will seem very foreign and weird for many reasons, the parens being just one of them.
I think having the ability to get your feet wet and start dabbling without an upfront investment is a good thing and the "jumping into the deep end" approach isn't for everyone, especially not for many beginners who at this point have only a very vague idea that a LISP might be for them and are already facing a number of new concepts that they need to get their heads around.
Parinfer requires no investment, Paredit requires some. Not much, but still. And going from one to the other as one feels drawn to explore the language is, I think, a perfectly natural transition, which requires no unlearning or changing of habits whatsoever, and as such it's also a more accessible path to getting into LISP. In my book, that's a good thing.
But here we're beginning to move into a general attitude/philosophy territory that's hard to argue about, so I'd be perfectly comfortable with agreeing to disagree and leaving it at that.
While deep inheritance hierarchies
may seem like a great way of
modelling your concepts when you
have a blank slate, it’s a
recipe for some extremely tight
and non-obvious coupling that
can deadlock refactoring attempts
in later phases once those concepts
have shifted and the original
model is no longer a good fit.
This is probably the best critique of nominal inheritance I've read. It really does capture the problem and nicely alludes to the struggle of arguing against an inheritance structure. That it usually starts with many benefits but can easily grow to a constraint.Part one: http://gmorpheme.net/lisp-in-small-pieces-of-clojure-part-1....
Part two: http://gmorpheme.net/lisp-in-small-pieces-of-clojure-part-2....
This continues a translation of various parts of Lisp in Small Pieces into Clojure. For earlier chapters, see:
Lisp in Small Pieces of Clojure - part 1.
Lisp in Small Pieces of Clojure - part 2.The only great book I'd like to see written in Lisp is CTM.