Learn::Raku::With
Learn Raku With: HTML Balls
Intro
Raku is, by far, the programming language I'm most excited about. It's powerful, expressive, extensible, and flexible enough to support whatever programming paradigm best suits a task. In fact, I gave a talk last year at FOSDEM about why Raku is the ideal language for writing free software. So it's fair to say that I think as many people as possible should learn the language.
Fortunately, Raku is pretty easy to learn (in the same way as chess or go β easy to learn; difficult to master) and existing Rakoons have written many great resources to help you teach yourself. The main docs do a good job of teaching the language (in addition to their primary role as a reference for more experienced Rakoons). There are also a number of books, including the in-progress Complete Course in Raku (funded via a grant from YAS and thus freely available). Programmers who aren't feeling up to working through a full book could also check out the Raku Guide or could Learn Raku in Y minutes. And if you get stuck on anything, the community is very willing to help out on IRC, Stack Overflow, or the r/rakulang subreddit.
The problem
But, despite all those resources, Raku is slightly harder to get started with than some other
languages in one way: There's not a built-in way to get started with beginner code in a way that
immediately produces visual results. If you're the sort of person who likes printing output to
STDOUT
, then it's easy to write your first several Raku scripts. But, if you'd like to display
shapes or do other visual tasks, Raku doesn't offer the same out-of-the-box experience as
languages like JavaScript, Racket, or
Pharo.
I got thinking about this the other day after reading a recent post on r/rakulang. The post's author described themselves as βan old FORTRAN programmer trying to teach himself rakuβ and asked whether there was any way to use Raku to recreate a bouncing balls demo that seemed like a good learning exercise. The consensus in the replies is that there currently isn't.
And that struck me as a real shame β I decided that there really ought to be a simple and visual way to get write a basic Raku program and see a ball bounce across your screen. So I decided to make one.
The solution: Learn::Raku::With::HtmlBalls
This repo contains the code for a Raku module that allows you to write simple Raku programs to display balls in a web browser. Here's how it works:
Install [Raku] and [Zef] if you don't have them already (I recommend the rakudo-pkg installation method), and make sure you have a recent enough version of Zef to support the Fez ecosystem (you probably do).
run
zef install Learn::Raku::With
to install this module.Write a script that imports this module, uses the
learn-raku
function (described below) to place/move balls, and then sleeps. Then run that script from your shell (e.g., withraku script.raku
).View the balls in your browser at
localhost:10000
(or set a different address with theLRW_HOST
andLRW_PORT
environmental variables).
That's really all there is to it!
The API
The point of this program is to help people learn Raku, not a custom API. So the options for
manipulating your balls are deliberately minimalist. Specifically, you get one object (Ball
) and
one function (learn-raku
).
Each Ball
has four mutable attributes:
x
- the distance from the left of the screen to the ball's center (as a percentage; 0 for the left edge, 100 for the right)y
- the distance from the top of the screen (also as a percent)radius
- the Ball's radius as a percent of the smaller of the screen's width or heightcolor
- a string expressing the Ball's color, with any valid CSS color value.
You can omit any or all of these attributes when making a new Ball; any ones you leave out will be filled in with random reasonable defaults.
The learn-raku
function accepts three named arguments.
run
- starts the server (with a True value) or stops it (with a False one)@balls
- changes the current Ball(s) to the ones you provide. If omitted, you start with one Ball.&map-fn
- a function that moves the Ball/produces new Balls based on the current ones. If omitted, the Balls don't move.
A few more words about the &map-fn
parameter. This function will be called 60 times per second
with all the Balls that are currently on the screen and its return value (which must be a Ball or a
List or Array of Balls) will be used as the Balls for the next frame. Actually, &map-fn
can be
used in two ways: it can take and return a single Ball, in which case it will be called once on
every displayed Ball β this form is convenient if you only have one ball or want all balls to obey
the same rule. Alternately, it can take an Array of Balls, in which case it will be called once
with the entire Array and should return a new Array or List.
That one function and its three arguments are the entirety of the API in this module β the rest is up to you (and all the power built in to Raku!)
Learn::Raku::With ... examples
The simplest script you can write is using this module is
use Learn::Raku::With::HtmlBalls;
learn-raku :run;
sleep;
This places a single Ball randomly on the screen. Or you could place two overlapping Balls like so:
use Learn::Raku::With::HtmlBalls;
learn-raku :balls[ Ball.new(:x(50), :y(50), :color<#f7347a>),
Ball.new(:x(50), :y(50), :color<rebeccapurple>)],
:run;
sleep;
If you want a Ball that moves, a simple option would be
use Learn::Raku::With::HtmlBalls;
learn-raku :map-fn(-> $ball { $ball.x += .05; $ball }), :run
# Remember that you need to return the new ball ^^^^, not just modify one
sleep;
You can check out the examples directory for a few more simple examples. PRs are welcome if you'd like to add more!
Learn::Raku::With ... error messages
The Raku community has a deep commitment to helpful error messages β in fact, we like to say that any error message that's LTA (Less Than Awesome) represents a bug. I really love this approach β especially when first starting out, it's very helpful to have the compiler/interpreter on your side.
So, for this module, I've tried to not only take embrace Raku's approach to awesome errors, but to actually turn it up to 11: I've augmented normal error messages with a bit more color, extracts from your script's source code, and extra info based on the Learn::Raku::With context. For example, in the last section I noted that you need to remember to return a Ball even if you modify one in place. Here's the error message that script would generate if you forgot:
image ./err-msg.png not found
Because Learn::Raku::With has more context about how it can be used, it can offer you more info when things go wrong β and hopefully better advice as well. I encourage you to play around and experiment; if things go well, you'll learn something new and if you get an error, you'll probably learn from that as well. If you run into any LTA error messages when using this module, please feel free to open an issue (either with this module for custom error or with Rakudo for the standard error messages it generates).
Learn::Raku::With ... your REPL
Speaking of playing around and experimenting, part of my goal for Learn::Raku::With was to build
something that you can use from Raku's
REPL (which you can access by
running raku
without any arguments on the command line or, most likely, from inside your
editor/IDE of choice).
And, sure enough, the using the same API described above in your REPL Just Worksβ’. Once you've run
use Learn::Raku::With::HtmlBalls
in your REPL session, you can call learn-raku
just as you
normally would β except that now the effects of your each function call are immediately reflected in
your browser and certain errors that would end execution of your script just return you to the REPL
prompt. Pretty much the only downside to working in your REPL is that, without line numbers to work
from, Learn::Raku::With can't print the exact code line of your error β but you probably just typed
it in anyway!
My hope is that learning Raku in a REPL-friendly way will help shorten your feedback loop and give you something that approaches true interactive development.
Learn::Raku::With ... the source code
I also hope that the source code for Learn::Raku::With can serve as a learning resource for more intermediate/advanced Rakoons. One problem I've often run into when learning new programming languages is that finding "medium" example programs can be a bit tricky. It's easy enough to find small programs that are well written (for example, on Rosetta Code or similar sites). And the language compiler or major frameworks or tools typically provide excellent examples of large programs. But finding a smallish-but-not-tiny program β one that's small enough to wrap your head around when you're still learning, but big enough to learn more advanced patterns β can be a bit more challenging.
I hope that Learn::Raku::With can fit in that middle category. Not counting error handling,
testing, or the HTML template, the program is contained in a single file that's shorter than this
README
. (At release, it's 118 lines of code + 32 comments + 25 blank = 175 total lines.) I've
also done my best to use a simple (arguably simplistic?) design β or at least as simple as possible
for a highly concurrent program. The program's high-level design is described in the
architecture.md document in this repo, but the short version is that it's
essentially a (very) simplified version of Phoenix LiveView
that streams JSON to a web browser at 60 fps β something it can only get away with because it's
designed to be run locally rather than over an HTTPS connection.
Learn::Raku::With ... other Rakoons
Tight feedback loops are great, but learning is an inherently collaborative process. If you get
stuck, please ask for help β either by opening an issue here, asking on the #raku IRC
channel (I'm codesections
on IRC and pretty
much everywhere else), or by posting a question to StackOverflow (the Raku tag is mostly
watched/moderated by Rakoons and thus tends to be a friendlier corner of the site).
And if you learn something from Learn::Raku::With or build something cool, I'd love to hear about it. It might make a good example to add to the examples folder, or it might just be a neat demo. But, either way, I'd be interested to see what you create.
Happy hacking!