Learning racket/scheme - how do you get to the practicing stage?

This is kind of a self-admonishing rant, I do not expect any comments unless you really feel compelled. Been lurking here for a while, posted a few times. I have programmed for quite a few years now, started in quick basic, then asm and Turbo Pascal on msdos and then progressing to C on Linux or SunOS or Tru64 or..., then Python, some Java, then Scala. Along the way I cursorily looked at Haskell and LISP (in college). Recently I picked up Scheme in the form of Racket. I consider myself to be well rounded in terms of computer science knowledge, there are many better programmers out there but I can hold my own in many Comp Sci discussions about concepts and implementations.

Yet, one thing I found is that Scheme is the simplest language (apparently, it is all just parentheses and a few constructs) but yet it somehow produces so much theory-reliant (I don't want to call it) complexity (but I have to for lack of better word), from continuations to macros to.... - all meant to allow you to run a full circle back to .... write simple yet elegant code. Starting with basic stuff like Little Schemer or Racket programming the fun way, I have found myself reading serious academic papers, then going to "Beautiful Racket" only to end up reading Fear of Macros and then ending up somehow on LOL book (Let Over Lambda) and then on LISP in small pieces - this whole "simple language" is so full of rabbit holes that bend your brain. I have always been able to just pick up a language and run with it practically "in no time" but with Scheme I find myself just adding more books and papers. It's almost as if I am prisoner of my own mind wanting more. Heh.

In any case, thanks for reading, just thought I wanted to say this in case someone else is struggling like I am.

15 Likes

Thank you for the post @maketo, I actually share your feelings at least partially, but I guess I ended up having a biased point of view :slight_smile: Let me explain.

I got started with Haskell in 2011, precisely because the language seemed so esoteric to me and manipulated mathy concepts directly. At the time, I was completing an engineering degree in Computer Science, and I was looking at research with quite an interested eye. Over the next couple of years, I came multiple times over instances of people saying that you need to have a PhD to be proficient in Haskell, laughed at them, until I realized in 2015 that I could teach a decent introduction to Haskell and that I had just got a PhD in Computer Science :smiley: My PhD was not in programming language theory, it was mostly in formal language theory, but I guess it still made me personnally ineligible for easily dismissing jokes about Haskell and PhDs.

I picked up Racket in 2020 mainly because I wanted my life to be 100% Lisp (I am an Emacs and Guix user), and because I found Haskell's type system somewhat restrictive for my very specific academic use. As you point out, Racket and Haskell have one salient similarity: there are quite a number of research topics people work on using these languages, even though the actual topics are different. I guess this is one of the reasons I got to like Racket.

After this disclosure-got-fuller-than-intended, I would like to actually give some feedback on your remark about theory-reliant complexity @maketo . I totally agree with you: open some Racket blog, or some Haskell blog (I haven't been following Haskell at all recently though), then open some Java blog or Python blog, and you'll get quite different vibes. In Python, people will show you how their code is beautiful, conforms with PEP8, and only consists of one line, because there already is a library doing precisely what they want. In Racket, people will show you how to do a web server with continuations, and then explain the minutiae of optimization, maybe with a couple syntax transformers here and there to streamline the final code. (That's my feeling, not a rant, and definitely not an accurate description of the state of the art :smiley: )

To me, this is a consequence of the different kinds of focus you may have in programming. On the one hand, you may want to build a tool to help you count money, store and handle medical data, etc., on the other hand you may want to think about ways of building such tools, yet on the other hand you may want to use programming as a support for thinking about stuff which is not necessarily directly related to programming itself (that's my focus). My strictly personal opinion is that you need different kinds of languages for different kinds of focus.

Funnily enough, to me it looks quite in line with the philosophy of language-oriented programming :stuck_out_tongue:

6 Likes

@maketo Thanks for writing this post. I can certainly relate! :slight_smile:

I came to Racket about two years ago and had learned over a dozen other languages before. Despite Racket being a "simple" language in a way, there are so many concepts and especially APIs that it's difficult to understand what's needed to write useful programs in comparison to more optional concepts. For example, so far I haven't used (needed) macros and continuations, but I think that "nonetheless" my code is relatively straightforward and comprehensible.

The documentation can be confusing at times, especially for Racket beginners. In particular I remember reading the documentation on structs and seeing a "casual" mention of "match transformers", without any idea what they are and whether I should know what they are.

To this day, I'm not sure if a "syntax transformer" is the same as a macro or if there are any subtle differences. Sometimes I think that explanations in the documentation are unnecessarily complicated, but I can't judge whether/when this impression is actually true.

By the way, I mentioned this before, but I think the Racket documentation should contain a glossary, which ideally should be easy to understand even if you're new to Lisps.

7 Likes

This is a very good point. I'm usually interested in solving "real" problems and I sometimes have the impression that Racket (or maybe the documentation on Racket?) can be unnecessarily confusing and complicated in this context. Still, I like coding in Racket because it has a certain "flow" to it that I haven't found in other languages so far.

1 Like

Hello!

You bring up a good point, one I have not thought about since I guess it is often implicit. Sometimes you try to solve a problem and sometimes you get stuck thinking about the problem of solving the problem :wink:

4 Likes

After all this, someone tells you - "Racket is still just a Scheme" so it can be as simple as you want it to be or as complicated as you make it.... :wink:

1 Like

Of course. :wink: The trouble is that this doesn't help if you come to Racket without learning Scheme first. :upside_down_face:

Actually, to get a better understanding of what "just a Scheme" means, I'm currently working through The Scheme Programming Language. And to enhance the experience, I'm using Chicken Scheme instead of Racket.

I think you can get the same experience within Racket by just learning from the little/reasoned/seasoned Schemer books?

To reply to the actual question ... :slight_smile:

If I remember correctly, I read the Racket Guide, but that wasn't enough for me to get an idea how idiomatic Racket code should/could be written. Therefore, I next went through the first two chapters of SICP, at which point I had at least an idea of how to work with Racket. After that, I decided to go beyond exercises and started my first Racket project, with occasional questions in the Racket Slack. I worked on other small projects after that.

At the moment, I think I'm sufficiently productive with Racket to write "real" code, but it sometimes frustrates me that there's so much more I don't have experience with.

2 Likes

I guess that's true. You could probably work through all the Scheme books with "just" Racket if you use #lang r5rs or #lang r6rs (for example to work with mutable pairs), but I also want to expand my horizon outside the Racket ecosystem. :slight_smile:

This a great idea! Let’s make it happen.

1 Like

I started something. :slight_smile:

3 Likes

Perhaps it's too late to reply to the original question, but my recommendation is to initially avoid the fancy stuff.

Continuations are a very deep rabbit hole. Just ignore them initially. Much later, you can start with let/ec that create an escape continuations, when you need an emergency exit button to escape from a few nested fors.

Macros are another very deep rabbit hole. Just ignore them initially. Much later, you can start with define-syntax-rule that is very straightforward and almost look like a #define in C. Even later you can try to understand what it is doing under the hood.

7 Likes

@maketo

This observation that the Racket language seems huge for new users is an important one.

The module and macro system of Racket allows anyone to extend the "core" language.
The normal boundary between what's provided by the language and user libraries more or less disappears in Racket.

There are obvious benefits of allowing anyone to extending the language.
It allows users to experiment with different implementations of the same concepts without
having to argue in committies over details before changes are made to a "blessed"
language implementation.

To illustrate the point: the current object system and the current pattern matcher are implemented as standard Racket libraries. The current object system is inspired by Java/Beta. However if a Racket user prefers the Common Lisp model, there is another object system available in Swindle.

In contrast: The Python language recently got pattern matching. It only took 30 years...

The downside of blurring the line between language and user libraries is that (from the documentation) it can be difficult to figure out which libraries are in common use and which are abandoned experiments (or simply rarely used). Every popular language has this problem to some degree (Python recently removed som batteries - and anyone writing JavaScript will know that npm is both a blessing and a curse).

Due to the way I found Racket, I tend to think of R5RS as an essential part of Racket.

Here is what I would focus on if I were new to the language:

  • R5RS
  • structures
  • pattern matching
  • for loops and comprehensions
  • module system
  • simple macros

The intention of "The Guide" is to provide an introduction to Racket. It does a good job. But. I think new users of the Racket documentation might have a hard time to see what's part of the Reference and what's part of the Guide. It's just too easy to click something while reading the Guide and end up in the Reference without noticing. Maybe a different color for the Guide (green?) could be used?

11 Likes

Hello! Thank you for your reply. Perhaps this is what is getting me hung up, well, at least partially. In most other languages you don't really have to think about continuations and macros and how they work. Additional problem for people (like me) who like to understand how things work is that once you start digging, it is a bottomless pit :slight_smile:

You are correct about the blurred line, however. For example, I started reading Beautiful Racket and the use of "br" language is obviously extensive. I realized at some point that its documentation is served the same way from the same URL as ordinary Racket documentation. Then the question came about - is br then a part of Racket? Is it "production ready"?

Thanks!

Thank you!

heh - it is an interesting remark about define-syntax-rule being the starting point :wink: - if you got down the rabbit hole of learning macros and read "Fear of macros", define-syntax-rule is one of those things you are told to avoid as a starting point. (4 Pattern matching: syntax-case and syntax-rules)

Butterick made the br language to make the exposition clearer.
In the appendix he recommends the use of #lang racket/base instead.
Not because there are problems with #lang br but because it's good practise
to use the smallest language needed.

https://beautifulracket.com/appendix/from-br-to-racket-base.html

5 Likes

I understand/agree. I only found that link after I asked Butterick the question of whether br is production ready, given that its documentation is hosted on Beautiful Racket - to me hosting these libraries/improvements/whatever you want to call them on the official language documentation website is a double-edged sword - after you have been around Racket for a while, you will eventually understand that not everything in the documentation is about "bare" Racket. On the other side of that coin, it is confusing as heck :slight_smile: for a beginner

1 Like

I agree it can be confusing. Maybe some kind of color coding would help? It's not obvious how to do it though.

On the bright side, having all documentation in one place has been important to build a culture where documentation usually is better than lists of functions generated from the source.

5 Likes

Maybe there's a misunderstanding here. Many if not most of the links on the documentation page don't refer to the Racket distribution but are generated from the documentation of packages submitted on the package server. I think that's a misunderstanding that can happen easily. I was also a bit surprised when a small package I wrote appeared on the documentation page. :wink:

I don't know any other language ecosystem that automatically lists the documentation of "external" packages on the main documentation page of the actual language distribution. I guess I like the approach, but at the same time it's confusing for newcomers to the Racket ecosystem.

Maybe there should be an easily visible note before the links to the documentation of external packages?