From efafb5556b8706204fa4cfc89800c6102a58862d Mon Sep 17 00:00:00 2001 From: comborico1611 Date: Tue, 16 Jun 2026 14:41:01 -0500 Subject: [PATCH 1/2] Create LISP Guide to Raku Not finished, but making sure this is what y'all want. --- doc/Language/LISP Guide to Raku | 547 ++++++++++++++++++++++++++++++++ 1 file changed, 547 insertions(+) create mode 100644 doc/Language/LISP Guide to Raku diff --git a/doc/Language/LISP Guide to Raku b/doc/Language/LISP Guide to Raku new file mode 100644 index 000000000..a3cc776bc --- /dev/null +++ b/doc/Language/LISP Guide to Raku @@ -0,0 +1,547 @@ +=begin pod :kind("Language") :subkind("Language") :category("migration") + +=TITLE LISP Guide to Raku + +=SUBTITLE A conversation about Raku with LISP in mind. + +=head2 Introduction + +The most notable thing that makes LISP charming and well-suited to +beginners is its clear positional syntax. You can always count on the +function coming first followed by its arguments: + +I + +=for code :lang + (function arg1 arg2) + +And something with a little more substance: + +I + +=for code :lang + (reverse (sort (union some-array))) + +This consistency found universally in the language is what has won LISP +its many users through the years, the world over. Well, I don't think +there is a programming language furthur from that principle than Raku. +So as someone that prefers LISP over all others, why do I think there is +something special about Raku? + +Sure, Raku completely obliterates the notion of a simple syntax, but +what is gained is readability of code due to a smart set of in-house +operators that lend toward concise instruction but flexible enough to +allow for intuitive programming of a more verbose manner. + +With this in mind, please observe our first piece of Raku code: + +Raku + + (reverse (sort (unique (@some-array)))); + +Mostly identical with Common LISP, with a few minor differences. LISP +uses the classical term "union", which is probably the mathmatical and +technically superior term. Whereas Raku goes for the simple and +practical "unique". And there is that email symbol in there. +But other than that, pretty similar. + +So the question arises: + +Is Raku LISP? The Raku FAQ section has the answer: + +Raku + + (not (not Nil)) + +BECAUSE... there is another way to do it. Which was the core philosophy +of Raku's predecessor and wildly successful programming language Perl. +This philsophy continues through its successor, Raku. + +=head2 The Raku Way + +Considering the previous code, here is the preferred way to write that +statement in Raku: + +Raku + +@some-array.unique.sort.reverse; + +Okay, so what's going on here? Object-oriented programming. At this +point, you may be thinking what I thought, "I don't like object-oriented +programming." But here is the kicker, Raku the language, even the +core is written in the style of object-oriented programming. And object- +oriented styling is literally in every jot and tittle. But Raku does not +force object-oriented styled programming. It can be written in that way, +along with other styles. + +And one of the benefits of a programming language written in O-O is +flexibility, in many different ways. And here one benefit is, there is +no doubt that this is a cleaner notation -- with the added benefit that +the left to right order of evaluation now reads naturally with the actual +sequence of execution. + +Programming languages are written for people nearly as much as for +computers. And what we've learned this handful of decades is that the +programming language that is cleanest to the user, is the most effective. + +Regardless of your choice of syntax, the noteworthy feature is Raku's +take on all this. Which is, as best as possible, avoid restricting users +of their personal methodology. TMTOWTDI, y'all --> there's more than one +way to do it. Because in the end, the best syntax depends on the +problem, and the flexibility to have options is best. + +=header2 Basics of Raku + +So as we just said "as best as possible to avoid restricting users" -- +there are certain things you'll need to have an open mind about. And +maybe after some time, you'll end up preferring. One of those things is +the ubiquitous sigil -- that @ symbol you saw. + +Sigils go before the name of a variable. Raku requires the use of the +sigil at the beginning of each and every variable. Raku has 3 basic +types of variables: scalars ($), hash tables (%), and arrays (@). + +So again, anytime you wish to use one of these variables, the variable +must be "titled" with its appropriate sigil. + +As somebody that likes the idea of static typing, I feel sigils are an +improvement on the concept, only more compact and completely +pervasive -- versus existing only in the function definition. But this +comes at the cost of always needing to type them. + +(As a EMACS and LISP guy, I gotta take a jab here at the founder of Perl +and Raku , who once said that he tried to use Emacs but then his pinkies +got tired. Well, typing all these sigils makes my index finger tired. +And Raku's just catching up to the long-held features of LISP! See, I'm +a lisper just like you. Now back to our discussion.) + +In LISP, the environment in total occurs within the parentheses -- +another charming aspect of the language. As previously stated, Raku is +descended from Perl which is descended from the programming language C. +In those languages, the environment is made up of predominately the +statement and the function body. + +The semi-colon is conceptually similar to the parentheses of LISP, in +that the syntax of the parentheses are the notation for the concept of +the expression. But in Raku, our building block is not the symbolic +expression found in LISP but "the statement", which serves as a single +(though often complex) instruction. + +Raku is operator rich, not just compared to Common LISP, but compared to +all other programming languages out there. By operators I mean any +in-house functions -- functions that are baked into the +language -- pre-defined. This will of course come with a steeper and +longer learning curve. But the reward is having the most tools that will +accomodate your thinking/programming style more than any other langauge +out there. + +Now because LISP users have the first and best REPL in the world, and are +accustomed to working within it, the code here will be syntaxed as if +working from Raku's REPL, unless otherwise noted. + +=header2 Lists + +We'll get started with the thing you are most familiar with: the list. + +Unlike in LISP, a list is created with the comma, not the parentheses. + +Behold, the Raku List: + +Raku + +1, 2, 3, 4 # a list of four elements +1,2,3,4 # spacing is not required + +So it doesn't look like much -- numbers and commas -- which is exactly +the point. Raku aims to make code as readable as possible. The less +characters on the screen, the easier it to read, and the harder it is to +introduce human error. And that's the bottomline. Much of the tenets of +the design of Raku stem from this principle. + +Here is a list of symbols: + +Raku + +'a', 'b', 'c', 'd' # as in LISP, symbols must be quoted + # Quote-words Circumfix Operator + +We must quote each symbol or else the system will go look for what the +symbol evaluates to, just like in LISP. + +The < > operator automatically quotes each symbol separated by space for +you. Anywhere things can be done easier, Raku developers tried to do +something about it. + +Parentheses take a second-row seat in Raku, and are used predominately to +establish grouping: + +Raku + +(1, 2), (3, 4) # a list of two lists +(1,2),(3,4) # again, spacing is optional + +So parentheses are essential in defining a group, but not in creating a +list. + +So as we said, Raku strives to be flexible and not get in the way of the +programmer, but that does come with a cost. There are at least two +caveats of having more than one way to do things: + +1) There is likely going to be a less optimal way. +2) The programmer will eventually face learning those multiple, less + optimal ways. + +An example of this is the following. + +The semi-colon can also be used instead of the comma, though less common, +less clean, and likely fraught for human error. + +Raku + +(1; 2); (3; 4) # equivalent to a (1, 2), (3, 4) + +(But I could be wrong, and maybe it has its merits somewhere.) + +Commas and semi-colons can be mixed: + +Raku + +(1, 2); (3, 4) # if you prefer a semi-colon separator + +And still speaking of preferences in syntax, another choice to make, +though unlikely for a LISPer, would be to avoid nesting parentheses by +means of the semi-colon: + +Raku + +(1, 2; 3, 4) # equivalent to ((1, 2), (3, 4)) + +Okay, so enough of this semi-colon stuff, and back onto the main trail. +What would happen if we tried these? + +Raku + +(1) # Returns: 1 +(1 2) # syntax error: two terms in a row +(1, ) # Returns: (1) + +Now I can simply tell you that the input (1) is a integer in a group, +not a list. And that the return of (1) is a list. But you don't need to +take my word for it: + +Raku + +(1).^name # Returns; Int +(1, ).^name # Returns: List + +The ^name method outputs the Type of the symbol given it. + +Also you can see from (1, ) that trailing commas are okay -- another +thoughtful consideration built-in to Raku. + +Lastly, the syntax error is strange to a LISP programmer because having +adjacent terms/expressions is what LISP is all about. I think an +equivalent error in LISP might be something like + +I +=for code :lang + +(some-function some-function) # or +(symbolp symbolp symbolp) + +(Though not quite the same since LISP can have same the symbol for both a +function and a variable, but hopefully you get the idea.) + +So we have established the rule that parentheses don't make lists. But +here is the one exception to the rule: the good 'ol empty list: + +Raku + +() # valid empty list +(,) # syntax error + +Just as in Common LISP, the symbol 'nil' and the empty list, (), are +equivalent to false, so it is in Raku. However, 'Nil' must be +capitalized, and true is not 't', but 'True'. And since there is a +'True' we must also have a 'False'. Additionally for false, we have +empty braces {}, and empty quotes "". And then there is 0. + +I know there are several things that are false, but we have one more, +which is that types (like List, Str, Int, etc) are interpreted as false. +I am not sure of the reasoning behind this, but I'm confident it has its +purpose. + +And just like in LISP all other symbols that are not false, are true, +so it is in Raku. + +Okay, so we got the basics of list construction down. Now, how do we +retrieve elements from them? Pulling out elements isn't as fun and +unique as a CADDR or a CDAAR. But here's how it is done in Raku: + +Raku + +(25, 50)[0] # OUTPUT: 25 +(25, 50)[1] # OUTPUT: 50 + +And should you mess up and index a non-existing address, Raku will just +auto-fill it for you: + +Raku + +(25, 50)[2] # OUTPUT: Nil + +(So besides being considered false, Nil can also be interpreted as a +non-critical failure.) + +Indexing a list that is nested inside an outer list: + +Raku + +((25, 50), (75, 100))[0;1] # OUTPUT: 50 +((25, 50), (75, 100))[1;1] # OUTPUT: 100 + +(notice how we are nesting parens now, thats because... I don't know.) + +Earlier, we used the quote-term operator, to avoid quoting each +term. But another feature this operator performs is grouping. +Consider the following: + +Raku + +(<25 50>, <75 100>, <125 150>) +# equivalent to ((25, 50), (75, 100), (125, 150)) + +Adding this auxillary symbol for grouping is easier on the eyes, don't +you think? + +Using the angle brackets, let's look at how indexing works on a list that +is two levels down. + +Raku + +((, ), (, ))[1;0;1] # OUTPUT: f + +Play around with this in the REPL if you don't get how this works. + +Raku even allows not FIFO, but popping? +say (1, 2)[*-1]; # says 2 +say (1, 2)[-1]; # Error + +Now the biggest difference in Raku that is going to throw you for a loop +is that lists are not mutable! + +Okay, it's time we move out of the List data type (which honestly is not +where the majority of the work is done in Raku) into Routines (functions) +by way of conditionals. + +The 'if' operator is pretty standard with the addition of some assisting +operators not found in LISP to reduce common work-arounds. + +Raku + +if 1 > 0 { "this code block executes" } +# OUTPUT: this code block executes + +We need to add braces around the term "say this", because 'if' requires +an evaluating environment, a code block, that executes if the condition +is true.] As we said before, in LISP, the code block already exists +within the parens. + +Additional conditions can be easily "stacked on": + +Raku + +if 1 > 0 and 1 + 2 == 3 { "block executes" } # OUTPUT: block executes + +('==' means, Is it equal?) + +Just as an aside, Raku's terminology for its functions comes from its +creator, Larry Wall, who chose to continue his terminology of Perl into +Raku. And I, in similar manner, as the author of this article, wish to +impart MY knowledge/take on the topic. + +LISP having close roots to the discipline of mathmatics via its biggest +influence , the mathmatician and inventor of Lambda Calculus, Alonzo +Church, the community was careful to distinguish terms. The book +Structures and Interpretions of Computer Programs teaches that +"functions" are the term for mathmatical principles, not arbitrary lists +of instructions to a computer program. In other words, functions are +mathmatical knowledge. In the programming languages Pascal and Ada, +"procedures" are "functions" that do not return a value. And lastly, +Perl alone has remained to use the term "routine", which is the most +accurate term for what is commonly called "functions". + +To be completely accurate, Perl (and by extension Raku) uses the term +"subroutine", preserving the distinguished upper level routine, MAIN, as +is consistent with the C family of programming languages. + +But the free world is the marketplace of ideas and terminology. And that +market has concluded that the word will be "functions". But this small +article is not the marketplace, and neither is Raku. So bear with the +terminology, please. + +Subroutines are declared via the term 'sub'. Subroutines do not have +sigils. + +Raku + +sub hello-world { say "Hello, World!" } + +Okay, so 'sub' is declaring a subroutine, and 'hello-world' is the name +of our routine. Notice how in the traditional C family, the list of +parameters is missing, the so-called Signature section of the routine. +It is missing because hello-world does not take any arguments. And in +Raku-fashion, any superfluous characters ought not be there. +And so it is. + +Then we enter the body of the routine with the braces. SAY is an +operator that outputs to STDOUT (prints onto the screen) whatever is in +either double-quotes or single quotes. Then 'say' returns a New Line +character. + +Notice how there is no semi-colon to end the statement. Because the +statement is the last statement before closing the body, it is not +needed. Again -- superfluous characters can go by the way-side. + +Also notice that because all this can exist on one line, there is no need +to indent in the standard fashion of a routine in C, C++, Java, etc. + +Now to execute this routine in the REPL: + +Raku + +hello-world # OUTPUT: Hello, World! + +Let's change some bits that we just discussed. Consider this routine: + +sub hello-name ($name) { + say "Hello, $name."; + say 'Scalar variables look like this: $name; +} + +So you can see we now have a routine that looks like a routine in C +because it is taking an argument, and has the indentation, because it is +now useful to use indenting. We now have two statements, which is why we +needed the semi-colon this time. And is often this case, a opportunity +to choose your preference here. And mine is to use a semi-colon on the +last statement, though it isn't required. + +Let's call the routine and give it an argument: + +Raku + +hello-name( "Bob" ) # OUTPUT: Hello, Bob. + Scalar variables look like this: $name + +First, we put our name in quotes. Just like in LISP, we are telling the +REPL not to try to go find the value behind this symbol. We could have +used single quotes, if we wanted. Because there is nothing to +interpolate. But double quotes are more common -- thus the muscle memory +favors them. + +If we didn't quote the name, we would have an error: Undeclared Name. + +Notice the difference in behavior of the single and double quotes. The +single quotes will not interpolate variables; that is, translate +variables. It prints what is literally in the quotes. + +Requesting input from the user is also very straight forward: + +Raku + +sub hello-name2 { + my $user = prompt "What is your name? "; + say "Hello, $user."; +} + +The first statement is a combination of declaring a variable and calling +the operator 'prompt'. MY is the operator that declares variables. +Assigning is, of course, done by '='. The variable is then initialized +the value of what was entered. + +Let's look at a LISP-looking statement: + +Raku + +my $c = 0; say (1, (unless 0 { $c = 42; 2; }), 3, $c); + +Read the code as: first we are declaring and initializing 'c' variable to +the value zero. End statement. Next, we're calling operator 'say' and +passing it four arguments: 1, some code, 3, and $c. + +SAY will output 1, 3, and the value of $c -- regardless of what the code +does. + +Now the code. + +We first see the operator 'unless'. This operator is +exactly the same as negating the 'if' statement. The if statement goes +as follows: if true {do this}. And negating, if not true {do this}. So +Raku has provided the option of using 'unless'. unless true {do this}. +Or in a more English way: {do this} unless true. + +So the term 'unless 0', in other words is, "we're going to do this". +Why? Because 'unless' is only executed when the condition is false. +And 0 is false. Therefore, everything in the block, the { }, will be +executed. $c will be assigned 42, and 2, being the last statement of the +block, will be returned to 'say'. + +And finally 'say' has all expressions evaluated and returns: +1, 2, 3, 42. + +Moving on from this rudimentry stuff, let's look at a behavior of Raku +that is more unique to the language than the norm, one which really +boggled my mind for hours. + +The routines of most programming languages perform what is known as +"call by value". If the argument given to a routine is a variable, the +VALUE of that variable is passed to the routine, not the VARIABLE. +However, when a variable is the argument of a routine in Raku, the +variable (and subsequently its value) becomes the argument. And as long +as execution is in the routine, the parameter is simply another name for +the variable existing outside the routine. So instead of values of +variables being passed to the routine, variables themselves are passed to +routines, not calling the routine with a value, but calling the routine +with the value's variable. + +Now this becomes an issue because the default behavior of variables being +passed to routines is that the variable will be protected from being +changed. Variables passed to routines are by default read-only, +constant, the value is locked being changed in any way. + +Let's look at an example: + +Raku + +sub call-by-variable ($alias-for-variable) { + say "The current value of the parameter is: $alias-for-variable"; + $alias-for-variable = $alias-for-variable[1]; + say "We just attempted to assign, not the parameter only, but also the + outside variable."; +} + +call-by-variable("Bob Ross") +# OUTPUT: The current value of the parameter is: Bob Ross + Cannot assign to a read-only variable... + +[I NEED SOMEONE TO EXPLAIN WHY THIS BEHAVIOR IS PREFERRED.] + +To change the behavior to call-by-value, we have a few options. First, +we can choose to truly rewrite the value, or we can make a copy of the +value, which is what most programming languages will do. + +Raku + +sub call-by-value ($value-of-variable is rw) { } + +sub call-and-copy ($value-of-variable is copy) { } + +This behavior does not apply to the 'for' loop. [WHY?] + +So this is not a complete tutorial in Raku, but here are a few closing +topics that will help you navigate your learning Raku. + +First and foremost, in the Raku documentation, operators are classified +by their position in syntax: prefix, infix, postfix, circumfix, +postcircumfix. This is critical information to know when trying to +access info. From 54a65f1bcf570b6e9e65b7962fe763bc9f59f3db Mon Sep 17 00:00:00 2001 From: comborico1611 Date: Tue, 16 Jun 2026 14:50:44 -0500 Subject: [PATCH 2/2] Update LISP Guide to Raku --- doc/Language/LISP Guide to Raku | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/Language/LISP Guide to Raku b/doc/Language/LISP Guide to Raku index a3cc776bc..03f17713d 100644 --- a/doc/Language/LISP Guide to Raku +++ b/doc/Language/LISP Guide to Raku @@ -1,3 +1,4 @@ +@librasteve =begin pod :kind("Language") :subkind("Language") :category("migration") =TITLE LISP Guide to Raku