I've lately had some success using vanilla emacs, Geiser and Guile (or MIT) Scheme. If you want to work through sicp, the little schemer [1], or my current favorite "Essentials of Programming Languages"[2], then that's the perfect setup. Racket will work too, but if you're using emacs anyway then it's just as easy to get going with Guile or MIT.
I'd recommend getting familiar with largely vanilla emacs[0] rather than a curated kit, but it will require a little bit of additional investment. Additionally, you'll be getting acquainted with emacs-lisp (elisp), so you'll be swimming in lisp languages.
I'm not a fan of VS Code and only use it for work when I have to (and then only when I can't use vim). I'm sure it'd work, vim too, but there are an awful lot of emacs/lisp resources out there and it's helpful to take advantage of what's available.
[1] https://www.amazon.com/Little-Schemer-Daniel-P-Friedman/dp/0...
[2] https://www.amazon.com/Essentials-Programming-Languages-Dani...
https://www.amazon.com/Little-Schemer-Daniel-P-Friedman/dp/0...
https://eprints.soton.ac.uk/254242/1/p_by_numbers.pdf
And the "The Little Schemer" book has a series of exercises that expose recursive thinking:
https://www.amazon.com/Little-Schemer-Daniel-P-Friedman/dp/0...
Hope this helps!
https://www.amazon.com/Little-Schemer-Daniel-P-Friedman/dp/0...
[0] https://www.amazon.com/Little-Schemer-Daniel-P-Friedman/dp/0...
The Little Schemer [2]
[1] https://tour.golang.org/welcome/1
[2] https://www.amazon.com/Little-Schemer-Daniel-P-Friedman/dp/0...
[1] - https://www.amazon.com/Little-Schemer-Daniel-P-Friedman/dp/0...
The Tandy/Radio Shack books for the Color Computer series (and it's astoundingly good LOGO implementation) were amazingly clear and concisely written with lots of examples, and because in those days even a disk drive wasn't a guarantee, all the examples were written to be hand-typed and experimented with.
There were even books in those days that aimed to teach kids machine language! [1]
That said, I think Djikstra and Felleisen may be slightly right about the long-term usefulness of old-fashioned BASIC and LOGO for learning, but there are a few books in modern languages that come close.
Hello World![2] was explicitly written to hearken back to those old manuals, by a father aiming to teach his 12-yo son programming with Python.
Land of Lisp[3] and Realm of Racket[4] also call to mind those old books as well, though they're targeting a bit older audience and have their quirks (LoL is a bit in-love with huge nested trees and a-lists in the examples, and Realm of Racket tends to gloss over a lot of the examples and expects you to just read the sample code rather than walking you through the process completely).
The Little Schemer[5] is also a fantastic little book that takes on the form almost of a set of brain-teasers, and teaches recursive thinking entirely by example and in methodical detail. The later chapters can be a bit stumpy, but if you go through the book step by step in regular sessions it builds on itself pretty well.
All of these are aiming at around the 12+ age range though, I don't think there's much out there anymore for anything younger.
[1] http://boingboing.net/2013/05/16/1983s-wonderful-introducti....
[2] http://www.amazon.com/Hello-World-Computer-Programming-Begin...
[3] http://www.amazon.com/Land-Lisp-Learn-Program-Game/dp/159327...
[4] http://www.amazon.com/Realm-Racket-Learn-Program-Game/dp/159...
[5] http://www.amazon.com/Little-Schemer-Daniel-P-Friedman/dp/02...
Here's how it works. Say we have a recursive function like map:
map f [] = [] -- We'll ignore the base case since there's no recursion here
map f (x:xs) = f x : map f xs -- This is the interesting part
We want to write this more primitively, without explicit recursion. How can we do that? Well, if it's possible at all, we obviously need to get rid of the map on the right hand side of the second case.How? Well, let's abstract over the recursive call, replacing it with a function that we'll add as parameter to our definition:
map' _ f [] = [] -- Still boring
map' g f (x:xs) = f x : g g f xs -- Pay attention for later!
(Read map' as "map-prime", i.e., a variant of the definition of map.)All we've done so far is replaced map' where it should be on the right-hand side of its own definition with g, and then added g as parameter of the function. We end up with a double g on the right-hand side because of that added parameter.
OK, now what? Well, we need somehow to make g be map', the thing we're defining. which means we need somehow to pass our definition of map' to itself, so that (in the second case) we'd end up with something that evaluates to:
map' map' f (x:xs) = f x : map' map' f xs
Then the right hand side would obviously be right; it's what we were shooting for at the start (assuming we can get map' map' to equal map, which is what we're trying to do). The left hand side looks a little strange [0], but it's just saying that we need the first parameter of our definition to be the the thing we're defining.So how do we make this happen? Well, what is map map f (x:xs)? It's map applied to itself, then to some other arguments we need. So the key, it seems, is to figure out how to apply map to itself. Well, in the lambda calculus that's pretty easy [1]:
why f x y = f f x y
That is, why is just lambda f. lambda x. lambda y. (f f) x) y
OK, so fix takes a function and applies it to itself (after applying it first to arguments x and y). Great. That's what we needed. Now we can take our defintion of map' (the one marked Pay attention for later! above) and do this: map = why map'
And I've re-used the name map there because we can easily show that this definition is equivalent to our original definition of map by showing that it reduces to the same expression: map f (x:xs) = why map' f (x:xs)
== (by def. of `why`)
map' map' f (x:xs)
== (by def. of `map'`
f x : map' map' f xs
Which, if you keep expanding the expression map' map' f xs, you will see is indeed equal to the definition of map.Voilà. So that wasn't too hard. It's basically two steps: (1) abstract over the recursive call, then (2) figure out how to pass the function you're defining to itself. If you look at the Y combinator, you'll see that that's exactly what's going on there.
If this didn't make a lot of sense to you, it's probably because I wrote it on my iPad at 4:30 in the morning. It really is just those two steps: abstract over the recursive call, then self-apply. ...
To get deeper into the recursive mindset (if you're not there yet) and to build up deliberately to the Y combinator, take a look at one of my favorite books on functional programming, The Little Schemer [2]. (And watch out for the jelly stains!)
------
0. And it's ill typed, but never mind that. It's not possible to define the Y combinator (or any other fixed-point combinator) in the simply typed-lambda calculus, so just imagine that my Haskell-style syntax is untyped, like the basic lambda calculus.
1. Although, again, there's no way to give fix a good type in the simply typed lambda calculus.
2. http://www.amazon.com/The-Little-Schemer-4th-Edition/dp/0262...
The book The Little Schemer is a great way to learn to think recursively. It has been 5 years since I read it, and I haven't kept the skill fresh, so I've probably lost most of it.
http://www.amazon.com/The-Little-Schemer-4th-Edition/dp/0262...
Later, I moved on to the Clojure books. Working through the Little Schemer was invaluable (and its bibliography is excellent too).
[1] http://www.amazon.com/Little-Schemer-Daniel-P-Friedman/dp/02...
[2] https://github.com/evanspa/TheLittleSchemer/blob/master/sche...
I'm a total noob with this stuff but I've been really happy with Clojure (and more recently ClojureScript/Om) :)
[0] http://www.amazon.co.uk/Little-Schemer-Daniel-P-Friedman/dp/...
http://www.ccs.neu.edu/home/matthias/BTLS/
http://www.amazon.com/The-Little-Schemer-4th-Edition/dp/0262...
http://www.amazon.com/The-Little-Schemer-4th-Edition/dp/0262...
"Maybe I would be confident in my skills to apply to some tech jobs. Or do some freelance work"
Don't expect to get "normal" tech jobs by the time you're good enough unless you can disguise your age, age discrimination is fierce in this field. But as noted by you and many others, there are many options.
I'd also add that at some point unless you've forgotten all your math and don't want to refresh it try Structure and Interpretation of Computer Programs (SICP) (http://en.wikipedia.org/wiki/Structure_and_Interpretation_of..., http://ocw.mit.edu/courses/electrical-engineering-and-comput...), everything you need is free and online. If it's a good enough fit for you it will teach you some foundational things that'll make you a better all around programmer and system designer. E.g. one way or another learn big O notation (https://en.wikipedia.org/wiki/Big_O_notation) and its significance.
Over time, get some breath. In my book that means try to learn the basics of these languages and concepts and their typical environments: Lisp and recursion (see SICP above, or alternatives on the Wikpedia page plus http://www.amazon.com/The-Little-Schemer-4th-Edition/dp/0262... specifically for recursion), C and pointers, HTML, Javascript and browser programming, and some database work, SQL/RDBMS preferred, I recommend PostgreSQL over any of the MySQL variants, but a simple key/value store or embedded SQL database would also get your feet wet. If you learn recursion and pointers you'll be way ahead of most people who believe themselves to be programmers.
Good luck!
http://www.amazon.com/Little-Schemer-Daniel-P-Friedman/dp/02...
[1]: http://www.amazon.com/The-Little-Schemer-4th-Edition/dp/0262...
Essentials of Programming Languages http://www.amazon.com/Essentials-Programming-Languages-Danie...
The Little Schemer http://www.amazon.com/Little-Schemer-Daniel-P-Friedman/dp/02...
http://www.amazon.com/Little-Schemer-Daniel-P-Friedman/dp/02...
The Little Schemer <http://www.amazon.com/Little-Schemer-Daniel-P-Friedman/dp/02...; and
Clause and Effect <http://www.amazon.com/Clause-Effect-Programming-Working-Prog....
Also a help is that the languages they use ('use' is a more appropriate word here than 'teach') — Scheme and Prolog, respectively — are much more mathematical in nature than typical mainstream languages are.
It's an excellent introduction to thinking recursively. The others in the series (The Seasoned Schemer, The Reasoned Schemer) are worth reading too.
It takes you more step-by-step than SICP and once you get more practice with those books, SICP will be much more paletable.
[1] https://www.amazon.com/Little-Schemer-Daniel-P-Friedman/dp/0...
[2] http://sarabander.github.io/sicp/