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

I'm not convinced that "choosing one basically locks you out of the other ecosystem" in general.

  • It does seem that you need to choose between big-bang or GUI/classes + message passing (or easy-gui), but that doesn't mean you can't also use functional structs. I'm doing this in a project now which uses easy-gui and observables for the GUI and functional (immutable) structs for the underlying data representation.
  • image and pict are (in some ways) compatible. I can't remember how I found this out, and I couldn't find the doc section I'm thinking of quickly, but in the same project I use procedures from both in a series of pict?s. I have a feeling draw is compatible, too—again, it seems to be a matter of piecing together how and where via the docs.
  • RE: 3 macro systems, I'm pretty sure syntax-rules/syntax-case are (or could be) built on top of procedural macros, and that syntax-parse is (or could be) built on top of either. And, frankly, there's nothing incompatible about them: a macro written with syntax-rules should work fine with a macro written with syntax-parse. The choice is about convenience for the implementor, I think.

Summary: the pieces tend to fit together pretty well, being somewhat orthogonal.

What I do miss is seeing how some pieces fit together. As mentioned, drawing all the correct connections between the image libraries is difficult; one needs to read carefully to see where the connections exist, and study the "types" to see what can cross which boundaries. The GUI system is so large that I struggle with this there as well, in spite of the many diagrams and such. 3rd-party libraries do differing jobs of explaining how they fit into the existing ecosystem, but the hyperlinks on the "types" help. Fear of Macros is wonderful precisely because it extracts and explicates the connections.

4 Likes

As a professional C programmer of more than 20 years who has dabbled in various Lisps over the years(mostly Common Lisp but some Scheme), I wouldn't say Racket is an easy language to learn. In some ways, I think Racket subjectively feels more difficult for programmers with more experience because we are more likely to immediately attempt challenging tasks. But perhaps it is even more challenging to become competent in C. I started that journey so long ago that it is hard to make an accurate comparison.

Now that I've spent a few years tinkering with Racket, here are a few things that frustrated me:

  1. Beautiful Racket probably gets credit for drawing me to try Racket in the first place, but once I attempted to actually create a #lang Beautiful Racket was both invaluable and frustrating at the same time. It is written at such an intro level that it was a pain to go through the whole thing just to find the pieces I was missing. It also uses its own syntax macros which make it frustrating to re-use code from or understand the equivalent using one of the standard macro systems. I think Beautiful Racket would be more useful if it just used define-syntax-rule and syntax-parse.

  2. The official documentation is great in a lot of ways, but the Reference can be cryptic at times. There are also a lot of unfamiliar terms, like chaperone, plumber, place, channel, ephemeron, etc. Sometimes these are used as if they were standard terms that the reader should know. When trying to accomplish a concrete task that you understand at the OS level requires researching several new terms or concepts, it can become a little frustrating.

  3. A number of fairly basic things are really complicated, like structs. The need to know about keywords like #:prefab and #:transparent just to have a simple struct that you can serialize or inspect is annoying. At least, I think I needed #:prefab to serialize my structs. Don't quite remember now because it is so damn complicated!

  4. I have to look up the syntax of the various for forms most of the time I want to use them. Once I discovered named lets I mostly stopped using for for anything besides their simplest use cases. I sometimes hit decision paralysis when faced with choosing between the various for and map forms.

  5. Hygienic macros are complicated. I see their benefits but they are not easy to learn. Same with pattern matching syntax. Doing anything beyond the basics in syntax-parse feels like having to learn a whole new language. That said, I still think the official docs should push people toward syntax-parse and downplay everything else besides maybe define-syntax-rule.

I hope this post doesn't come across as too negative. I don't regret the time I've spent learning Racket. I picked Racket for a reason and I'm still happy with my choice. I also must praise the Racket community. Help was always available when I needed it. Maybe it's just my self-reliant nature, but I just wish I hadn't had to ask for help so often.

My advice to anyone learning Racket is to stick to a subset of the language and try to avoid rabbit holes until you really need to delve deeper and have the time to invest in it. When you are ready to take on macros -- I'd delay this for as long as possible unless you are creating a new language -- just learn syntax-parse and use it for everything.

8 Likes

I tend to agree here. There are advanced concepts and basic concepts in every language. I know it is a worn out example but most new Scala programmers do not assimilate the concept of monads on their 3rd day of learning the language, although they get to use the concept from the start through various instances of it in the language (without explicitly being told or being aware of it) - and somehow this works in Scala (as in, it is hidden until it is not - you do not feel compelled to dive in immediately). I think this difference is what trips me up so much with Racket - there is no "layering" like this obvious to me in it - it is an all or nothing proposition (at least for me) when learning the language :slight_smile:. Maybe I am wrong, it's not like you cannot live without explicitly mastering continuations .... or can you? :wink:

2 Likes

So far in Racket I've written a gopher server, a graphical gopher and gemini client, and an implementation of the "magic" language used by the Unix file command... and I haven't touched continuations! I also haven't written any code using contracts, futures, or places. The latter three I plan to make use of at some point, but I doubt I'll write any code using explicit continuations unless I somehow need it for a language implementation.

I don't feel like I have a thorough understanding of Racket's exceptions or object system either, but I know enough to make use of them. If there's a project you want to write, just get started and learn as you go!

3 Likes

I'm not convinced that "choosing one basically locks you out of the other ecosystem" in general.

Its entirely possible that I'm wrong. I was trying to think of examples that I ran into previously, but I didn't check to make sure that this was the case. Non the less, even if these things are possible it wasn't obvious to me. Let me check.

It does seem that you need to choose between big-bang or GUI/classes + message passing (or easy-gui), but that doesn't mean you can't also use functional structs.

I agree that you can use functional structs with the GUI framework. I meant something more like embedding big bang in a GUI or putting class based GUI elements into a big-bang project. That seems like a pretty abstract thing to do and I'm trying to remember exactly where I ran into the need for it. I should also mention that I'm not good at using the class system and GUI stuff since most of the teaching material (2htdp, realm of racket) I've encountered uses big-bang and functional structs. When I tried to use the GUI stuff it felt like I had to start over because I didn't know how to transition between them gradually. I think that's more what I'm complaining about? I find this stuff difficult to express for some reason.

image and pict are (in some ways) compatible. I can't remember how I found this out, and I couldn't find the doc section I'm thinking of quickly, but in the same project I use procedures from both in a series of pict? s.

When I was talking about pict and image I meant they weren't compatible in the sense that they have a lot of redundant functionality that I thought couldn't work on the other's datatype or something. That said, I just tried doing

(require 2htdp/image)
(require (only-in pict hc-append))

(hc-append
 (wedge 60 60 "outline" "purple")
 (circle 20 "solid" "blue"))

and that worked, so I guess I'm wrong. Also this tutorial does show pict, racket draw, and the GUI system being used together pretty seamlessly. The thing is I don't know how I can figure out how to use them all like that. I suppose I would need to learn the inner workings of all libraries and how exactly they build on top of each other?

Somehow it feels like too much, especially since I went through a book or two on using racket already. I mean those books did teach me well so I can use racket for a lot of stuff. But then to use other parts of it I have learn a very different approach, but I don't feel like I'm gaining new capabilities per se. Its more like learning stuff I already know how to do in a different, more complicated, and less restricted manner. I have to step back to proceed, and the value of the original approach is now less obvious, in that I don't know how it will go together with the other approach. So even if the approaches are compatible it doesn't feel like they are? Does that make sense?

1 Like

Yes, I think we agree on the part that it is difficult to sometimes see how the pieces fit together.

One approach that so far has helped RE: the title question is to just write programs :slight_smile: Eventually I get curious enough to explore a topic, be it one I'm familiar with in other contexts, have only read about, or am guessing at. Wherever I go, if (when) the documentation isn't sufficient, there are people willing to help. The challenge I foresee is capturing that help in a useful way. But I think the more time I spend with the rabbit holes the more they appear to make sense. Of course, I haven't gotten into some of the truly deep ones yet.

3 Likes

Although I agree it helps, it would be better if there was less frustration involved. :wink: In addition, it's a bit sad if people give up because of this frustration before it would be reduced enough by writing more code.

I don't disagree. The problem that pushed me to even write the original self-admonishing rant :wink: is that I read all this stuff and even after spending months on it, I am still unclear where to start. I am starting to think that after 30+ years in front of a computer, degrees and a career in scientific computing and software engineering, I am essentially too dumb to learn Racket. I feel like I spent half the time on Scala and was productive immediately and then the other half of that time I took to learn advanced stuff in the language. At this point, the time I spent on Racket (via beautiful racket and reading all sorts of papers and write ups) - I could have spent on, for example, Rust and would probably be a productive advanced Rust programmer (not that I want to be one :wink: ). With Racket, I feel like learning it is like that rain that keeps circling the field and the farmer needs it but the rain never comes.

Golly! That's a terrible thing to say. It sounds to me (forgive me if I haven't read your posts carefully) as though you've spent lots of time reading about various challenging and deep parts of the language, but not so much time just writing programs in the language. Am I wrong?

1 Like

@maketo ::

While I feel your pain as I said before, I am lost at your comparisons of learning Racket with say Rust
and such languages.

I have taught Racket with macro programming to (mostly) freshmen (2n sem) based on an HtDP/2e course
with a quick read of Realm of Racket. Some built amazing things in 8 weeks after an 8-week introduction (a
semester). Just to give one example, one student built a language for defining small languages in which
students can solve homework problems in a music theory course. (The programs are checked statically,
they don’t run). Some of these students had nothing but the fall semester (HtDP/2e) under their belt.

I have taught Rust to (mostly) self-selected seniors; most were amazing. The goal was to either add a
Rust component to an existing system or to replace a C component with a Rust component. Rust’s type
system definitely posed a steep learning curve. (My course co-instructor's dissertation deals with key
concepts in this world (affine types) so we pretty much knew what was going on). The students did well
but the freshmen projects looked (on the average) far more impressive. What made Rust learnable at
all is that, in essence, it’s mostly pedestrian once a learner groks the type system.

Perhaps I should write down the bridge that I used for the first course. The key really is to “slice” thru
the language with a goal in mind:

— plain old batch programming
— plain old GUI programming
— simple web programming (as a client)
— experimentation with notational definitions (simply macros) for advanced features (e.g. your own generators)

[[ The above four are essentially the topic of Realm though using the teaching GUI language (universe)
and not the Racket GUI language, a gap I mentioned before. ]]

— writing interpreters and modeling other languages
— web programming with a full understanding of the continuation model

[[ I think there are decent tutorials for this. ]]

— typed programming

[[ Gap. ]]

#lang implemetation

— embedded/hosted language implementation

[[ This stuff is quite advanced. It’s where Beautiful Racket would work best as things stand. ]]

1 Like

I guess the crucial difference between @maketo 's (and to some extent my) experience vs. your students' is that the students had your guidance. I assume you showed the students what to learn in which order and answered their specific questions when they had them. On the other hand, if you just get into the Racket ecosystem on your own (even with some help from the Racket Slack), it's difficult to see the forest for the trees and to decide what's directly important and what can wait until later.

If I remember correctly, I worked through (most) of the Racket Guide, but as soon as I started to write my own "actual" programs, I wasn't sure what I should learn to which extent. I think it was (relatively) easy for me to write the basic functionality, but I thought I should add contracts because "every" library had them. Then the chapter on contracts in the Racket Guide didn't explain enough of what I needed, so I dived into contracts in the Racket Reference, which is much more extensive. I don't remember the details now, but I can imagine I went further and read about other topics I had seen in the contracts documentation, sometimes out of curiousity, but also because I thought I'd need the information.

I also think it depends on how you interpret the "practicing stage" in the topic's title. If you understand it as writing a program that works just well enough, it's one thing. On the other hand, if you want to do everything "right" to publish your code as a package or even use it in production, the stakes are higher and if in doubt you learn too much instead of too little.

4 Likes

Well, I write small stuff but I am working on a large project at work where I have the freedom to dictate timing, choice of language, everything - basically it is my brainchild and I have full freedom (and I can ask developers working for me to learn whatever language I feel will be necessary). Months later after I started on Racket (in preparation for this project) - I still cannot bring my brain into an organized/coherent effort to attack this properly - in Racket. And believe me, I want to. Yes, I know other people are doing it, so naturally, I conclude it must be me :). Please, do not misunderstand my initial post - it is more of an admission / question that maybe a certain type of a person would have more trouble learning the language than another type of a person. I was just wondering if it is only me or are there others who may feel the same. Judging by the thread that resulted - maybe there are a few more like me - but for the most part people are not having trouble mastering the language/ecosystem and using it in large projects at work (?). Thanks!

p.s. the other part of all this is that if I choose Racket as the language of choice on this project, I have to be able to slice through the fog while teaching my other developer or three about Racket - show them what to look at and what to ignore and shorten their path from A to Z.

Perhaps I am tainted too much by "classical" procedural/OO "commercial" languages to be able to make these determinations? :slight_smile: Obviously, someone like you who has much more (language) experience - has a totally different vantage point. I guess if all you have done is work with languages that all have "similar" features and structures (how much of a leap is it to really go from C to Java or Python to Scala or Rust as opposed to from C to Scheme or just learn Scheme as first language?) - maybe being faced with a more "rabbit hole-y" language (sorry, new concepts being invented here as we go) is a bit of a bigger challenge. My apologies, I guess I don't have any defense as to why I would think what I said about Rust being easier to learn (if I really think about it) but I just feel like it would not be a leap for someone who is already coming from a typed/procedural/OO language (e.g. Scala, which itself was not a problem to learn).

1 Like

Perhaps this is what it is. I learned ALL the languages I have ever learned by myself - be they foreign spoken languages or programming languages and this is the first time in my life that I am stumped. I find the documentation to be esoteric (for lack of better word), almost as if it was written by machines or deities (the same thing? haha) and handed down in what seemed a very logical and coherent content to the creators. The last language I learned (and used on large commercial projects) before going into Racket was Scala and even the original book by Odersky is super readable, feels coherent and logical, progresses from one topic to the next with ease and there are no ifs, buts or ands while you are working through it. You can then jump to something like the "Red book" - Functional programming in Scala where you realize slowly but methodically, chapter by chapter, that some of the stuff you have been using as a "beginner Scala guy" are instances of "complicated" concepts like the (in)famous monads, you learn that functors are not a scary thing etc. etc. The same thing happened to me when learning Pascal - I seem to remember Wirth had a book about it when I was learning it and it seemed super simple back then. Same with C and K&R book - simple language, simple and short book.

Dunno, I cannot put my finger on it but other languages I have been exposed to have a "natural progression of complexity in exposition" (I invented another term here), Racket's docs just seem like they came out of a teleprompter with no coherency or prioritization. All chapters seem to matter in the docs and yet you are apparently free to choose what to use and what not to use - you can apparently get by being a programmer without half the stuff until you are ready but then there is a corpus of material/discussion that says otherwise. My brain looks at these contradictions (obvious apparently only to me) and it screams "does not compute, does not compute"! :slight_smile:

1 Like

Not having a TA or a professor is a disadvantage of being an independent learner.

There are things you can do to mitigate this:

I hope this helps.

3 Likes

There is certainly room for more intermediary materials.

Personally, I think we need a a Racket version of Practical Common Lisp [1].
Writing a book is a large time commitment though.

Maybe it would be easier to gather people to make a set of intermediate tutorials?

You mention K&R. The book "The Scheme Programming Language" [2] is probably the closest when it comes to mathcing the K&R style.

[1] Practical Common Lisp
[2] The Scheme Programming Language, 4th Edition

2 Likes

I'd say there is room for a Racket book written by a person who wants to introduce software developers into the language in a methodical manner. I keep hearing Scheme is a simple language - in fact, when you "complain" about Racket being complicated, you are told you can always revert to R5RS - which to me is not the answer - nobody wants to rebuild ALL the functionality ALL the time from scratch; meaning, I don't want to always start from 6 basic atomic constructs in every project and reinvent the wheel. I don't mind the ecosystem being "colorful" (for lack of better term) but there has to be a clear path for people to get into the language AND ecosystem and become productive quickly.

Case in point is Scala - language is fairly coherent (although there are irritating things like implicits where you have to "remember" what the compiler is doing behind your back - which I feel is a bit of a conceptual violation of a "functional" language). The libraries on the other hand are a bit of a chaos but at least the language is self-contained.

I actually would not mind volunteering on writing chapters if we could all agree what this mythical book would be, assuming there would be help available to proofread, offer advice, answer questions along the way etc.

p.s. one thing that always irritated me about Common Lisp is the amount of switches /parameters to functions - sometimes these parameters would be contradictory to each other as well - the whole premise of all these LISP-y languages is simplicity and then in practical terms the functions end up with 18 arguments and there are 16 ways to do the same thing - I suppose if your professional life depended on it, you would learn all these or keep a reference constantly handy; I think at some point you find choice to be good but as Germans say - he who has choices, has the doldrums (paraphrasing)

1 Like

I don't use Discord and this Discourse instance didn't exist during the most difficult part of my "startup time." That said, I have been using the Racket Slack to ask questions. But I can't ask questions before I've understood the big picture about the topic of the question. So being able to ask questions doesn't shorten the learning process much; it only helps when I can't find the information I want and am stuck. Also, sometimes even if I could ask a question, I don't want to bother others with my questions until I tried to find the answer myself. (I think that's "normal" culture among software development communities, but the Racket community seems to be more relaxed about this, as I meanwhile learned. :slight_smile: )

In a way it's ironic, but after looking through your (good) list, I'm reminded that the problem is not that information on Racket doesn't exist. Rather, the concrete information is often difficult to find and if you do, you still need to read and understand it.

I guess that's a major difficulty when learning Racket: There are so many concepts, but many of them are kind of foreign, even if you have a lot of experience in "non-lispy" languages. (*) Then, since the concepts are so unlike the ones you're familiar with, you still need to read and understand them to know that you don't need them! In other words, even if you don't need the knowledge about a topic, you still need to invest the time as if you did need the knowledge.

(*) Here's a list of some topics you come across in the Reference: contracts (with the sub-topics flat contracts, contract combinators, impersonator contracts), custodians, executors, wills, prompts, phase, place, reader, writer, sequences vs. streams, print vs. write vs. display. Some of these concepts are complex and have many pages of associated documentation. In some cases the concepts per se aren't so difficult, but you still need to read a lot of documentation to find out if they help with a concrete problem you want to solve.

1 Like

I get what you mean!

Yes, the Racket Reference is "just" a reference. In my opinion, it's useful when you want to look up details on something you read and understood before, but it's often hard to initially learn about a topic from the reference.

Efforts https://racket-stories.com, https://racket-news.com, https://benknoble.github.io/racket-slack-archive/ and Racket Wiki are all attempts to surface information that is otherwise hard to find.

I don't know half the concepts listed but I am confident that if I asked what a custodian, executor, or will someone would point me in the right direction, either in the form of an answer, or a resource that helps me.

I think that also applies to larger projects; if I said I wanted to make X then someone would be able to point me on the right direction. (where X is something I literally have no idea where to start - e.g. a windows service)

If I say I want to make something, but I don't know what, then it is much harder for people to offer concrete help. Maybe check https://github.com/racket/racket/wiki/Intro-Projects for ideas.

In my mind about two thirds of the book covers the same ground as the Racket Guide, and I don't think there is a need to replicate that. (contributions to the guide - more examples - or any other part of the documentation are welcomed)

I do think the Practicals in Practical Common Lisp fit the category of intermediary materials:

  1. Practical: A Simple Database
  2. Practical: Building a Unit Test Framework
  3. Practical: A Portable Pathname Library
  4. Practical: A Spam Filter
  5. Practical: Parsing Binary Files
  6. Practical: An ID3 Parser
  7. Practical: Web Programming with AllegroServe
  8. Practical: An MP3 Database
  9. Practical: A Shoutcast Server
  10. Practical: An MP3 Browser
  11. Practical: An HTML Generation Library, the Interpreter
  12. Practical: An HTML Generation Library, the Compiler

Looking at the list of PCL practicals, I'd suggest a Racket version of Practical Common Lisp would have a different set of practicals.

So I have some questions:

What practicals would a Practical Racket book include?

What Racket practicals already exist?

I think authentication for integrating with a cloud service (as server or client) would be a modern practical that didn't exist as much in 2005 as it does today. e.g. bot, cloud service (say speech recognition), or online application api (GitHub, Google sheets, etc.)

Kind regards,
Stephen

PS: I think @EmEf has suggested the R language 'Vignettes: long-form documentation | R Packages' as an approach to intermediary materials: e.g. https://github.com/tidyverse/dplyr/tree/main/vignettes

2 Likes