forked from adambard/learnxinyminutes-docs
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathraku.html.markdown
2274 lines (1813 loc) · 83.9 KB
/
raku.html.markdown
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
---
category: language
language: Raku
filename: learnraku.raku
contributors:
- ["vendethiel", "http://github.com/vendethiel"]
- ["Samantha McVey", "https://cry.nu"]
---
Raku (formerly Perl 6) is a highly capable, feature-rich programming language
made for at least the next hundred years.
The primary Raku compiler is called [Rakudo](http://rakudo.org), which runs on
the JVM and the [MoarVM](http://moarvm.com).
Meta-note:
* Although the pound sign (`#`) is used for sentences and notes, Pod-styled
comments (more below about them) are used whenever it's convenient.
* `# OUTPUT:` is used to represent the output of a command to any standard
stream. If the output has a newline, it's represented by the `` symbol.
The output is always enclosed by angle brackets (`«` and `»`).
* `#=>` represents the value of an expression, return value of a sub, etc.
In some cases, the value is accompanied by a comment.
* Backticks are used to distinguish and highlight the language constructs
from the text.
```perl6
####################################################
# 0. Comments
####################################################
# Single line comments start with a pound sign.
#`( Multiline comments use #` and a quoting construct.
(), [], {}, 「」, etc, will work.
)
=for comment
Use the same syntax for multiline comments to embed comments.
for #`(each element in) @array {
put #`(or print element) $_ #`(with newline);
}
# You can also use Pod-styled comments. For example:
=comment This is a comment that extends until an empty
newline is found.
=comment
The comment doesn't need to start in the same line as the directive.
=begin comment
This comment is multiline.
Empty newlines can exist here too!
=end comment
####################################################
# 1. Variables
####################################################
# In Raku, you declare a lexical variable using the `my` keyword:
my $variable;
# Raku has 3 basic types of variables: scalars, arrays, and hashes.
#
# 1.1 Scalars
#
# Scalars represent a single value. They start with the `$` sigil:
my $str = 'String';
# Double quotes allow for interpolation (which we'll see later):
my $str2 = "$str";
# Variable names can contain but not end with simple quotes and dashes,
# and can contain (and end with) underscores:
my $person's-belongings = 'towel'; # this works!
my $bool = True; # `True` and `False` are Raku's boolean values.
my $inverse = !$bool; # Invert a bool with the prefix `!` operator.
my $forced-bool = so $str; # And you can use the prefix `so` operator
$forced-bool = ?$str; # to turn its operand into a Bool. Or use `?`.
#
# 1.2 Arrays and Lists
#
# Arrays represent multiple values. An array variable starts with the `@`
# sigil. Unlike lists, from which arrays inherit, arrays are mutable.
my @array = 'a', 'b', 'c';
# equivalent to:
my @letters = <a b c>;
# In the previous statement, we use the quote-words (`<>`) term for array
# of words, delimited by space. Similar to perl's qw, or Ruby's %w.
@array = 1, 2, 4;
# Array indices start at 0. Here the third element is being accessed.
say @array[2]; # OUTPUT: «4»
say "Interpolate an array using []: @array[]";
# OUTPUT: «Interpolate an array using []: 1 2 3»
@array[0] = -1; # Assigning a new value to an array index
@array[0, 1] = 5, 6; # Assigning multiple values
my @keys = 0, 2;
@array[@keys] = @letters; # Assignment using an array containing index values
say @array; # OUTPUT: «a 6 b»
#
# 1.3 Hashes, or key-value Pairs.
#
# Hashes are pairs of keys and values. You can construct a `Pair` object
# using the syntax `key => value`. Hash tables are very fast for lookup,
# and are stored unordered. Keep in mind that keys get "flattened" in hash
# context, and any duplicated keys are deduplicated.
my %hash = 'a' => 1, 'b' => 2;
# Keys get auto-quoted when the fat comma (`=>`) is used. Trailing commas are
# okay.
%hash = a => 1, b => 2, ;
# Even though hashes are internally stored differently than arrays,
# Raku allows you to easily create a hash from an even numbered array:
%hash = <key1 value1 key2 value2>; # Or:
%hash = "key1", "value1", "key2", "value2";
%hash = key1 => 'value1', key2 => 'value2'; # same result as above
# You can also use the "colon pair" syntax. This syntax is especially
# handy for named parameters that you'll see later.
%hash = :n(2), # equivalent to `n => 2`
:is-even, # equivalent to `:is-even(True)` or `is-even => True`
:!is-odd, # equivalent to `:is-odd(False)` or `is-odd => False`
;
# The `:` (as in `:is-even`) and `:!` (as `:!is-odd`) constructs are known
# as the `True` and `False` shortcuts respectively.
# As demonstrated in the example below, you can use {} to get the value from a key.
# If it's a string without spaces, you can actually use the quote-words operator
# (`<>`). Since Raku doesn't have barewords, as Perl does, `{key1}` doesn't work
# though.
say %hash{'n'}; # OUTPUT: «2», gets value associated to key 'n'
say %hash<is-even>; # OUTPUT: «True», gets value associated to key 'is-even'
####################################################
# 2. Subroutines
####################################################
# Subroutines, or functions as most other languages call them, are
# created with the `sub` keyword.
sub say-hello { say "Hello, world" }
# You can provide (typed) arguments. If specified, the type will be checked
# at compile-time if possible, otherwise at runtime.
sub say-hello-to( Str $name ) {
say "Hello, $name !";
}
# A sub returns the last value of the block. Similarly, the semicolon in
# the last expression can be omitted.
sub return-value { 5 }
say return-value; # OUTPUT: «5»
sub return-empty { }
say return-empty; # OUTPUT: «Nil»
# Some control flow structures produce a value, for instance `if`:
sub return-if {
if True { "Truthy" }
}
say return-if; # OUTPUT: «Truthy»
# Some don't, like `for`:
sub return-for {
for 1, 2, 3 { 'Hi' }
}
say return-for; # OUTPUT: «Nil»
# Positional arguments are required by default. To make them optional, use
# the `?` after the parameters' names.
# In the following example, the sub `with-optional` returns `(Any)` (Perl's
# null-like value) if no argument is passed. Otherwise, it returns its argument.
sub with-optional( $arg? ) {
$arg;
}
with-optional; # returns Any
with-optional(); # returns Any
with-optional(1); # returns 1
# You can also give provide a default value when they're not passed. Doing
# this make said parameter optional. Required parameters must come before
# optional ones.
# In the sub `greeting`, the parameter `$type` is optional.
sub greeting( $name, $type = "Hello" ) {
say "$type, $name!";
}
greeting("Althea"); # OUTPUT: «Hello, Althea!»
greeting("Arthur", "Good morning"); # OUTPUT: «Good morning, Arthur!»
# You can also, by using a syntax akin to the one of hashes (yay unified syntax!),
# declared named parameters and thus pass named arguments to a subroutine.
# By default, named parameter are optional and will default to `Any`.
sub with-named( $normal-arg, :$named ) {
say $normal-arg + $named;
}
with-named(1, named => 6); # OUTPUT: «7»
# There's one gotcha to be aware of, here: If you quote your key, Raku
# won't be able to see it at compile time, and you'll have a single `Pair`
# object as a positional parameter, which means the function subroutine
# `with-named(1, 'named' => 6);` fails.
with-named(2, :named(5)); # OUTPUT: «7»
# Similar to positional parameters, you can provide your named arguments with
# default values.
sub named-def( :$def = 5 ) {
say $def;
}
named-def; # OUTPUT: «5»
named-def(def => 15); # OUTPUT: «15»
# In order to make a named parameter mandatory, you can append `!` to the
# parameter. This is the inverse of `?`, which makes a required parameter
# optional.
sub with-mandatory-named( :$str! ) {
say "$str!";
}
with-mandatory-named(str => "My String"); # OUTPUT: «My String!»
# with-mandatory-named; # runtime error: "Required named parameter not passed"
# with-mandatory-named(3);# runtime error: "Too many positional parameters passed"
# If a sub takes a named boolean argument, you can use the same "short boolean"
# hash syntax we discussed earlier.
sub takes-a-bool( $name, :$bool ) {
say "$name takes $bool";
}
takes-a-bool('config', :bool); # OUTPUT: «config takes True»
takes-a-bool('config', :!bool); # OUTPUT: «config takes False»
# Since parenthesis can be omitted when calling a subroutine, you need to use
# `&` in order to distinguish between a call to a sub with no arguments and
# the code object.
# For instance, in this example we must use `&` to store the sub `say-hello`
# (i.e., the sub's code object) in a variable, not a subroutine call.
my &s = &say-hello;
my &other-s = sub { say "Anonymous function!" }
# A sub can have a "slurpy" parameter, or what one'd call a
# "doesn't-matter-how-many" parameter. This is Raku's way of supporting variadic
# functions. For this, you must use `*@` (slurpy) which will "take everything
# else". You can have as many parameters *before* a slurpy one, but not *after*.
sub as-many($head, *@rest) {
@rest.join(' / ') ~ " !";
}
say as-many('Happy', 'Happy', 'Birthday'); # OUTPUT: «Happy / Birthday !»
say as-many('Happy', ['Happy', 'Birthday'], 'Day'); # OUTPUT: «Happy / Birthday / Day !»
# Note that the splat (the *) did not consume the parameter before it.
# There are other two variations of slurpy parameters in Raku. The previous one
# (namely, `*@`), known as flattened slurpy, flattens passed arguments. The other
# two are `**@` and `+@` known as unflattened slurpy and "single argument rule"
# slurpy respectively. The unflattened slurpy doesn't flatten its listy
# arguments (or Iterable ones).
sub b(**@arr) { @arr.perl.say };
b(['a', 'b', 'c']); # OUTPUT: «[["a", "b", "c"],]»
b(1, $('d', 'e', 'f'), [2, 3]); # OUTPUT: «[1, ("d", "e", "f"), [2, 3]]»
b(1, [1, 2], ([3, 4], 5)); # OUTPUT: «[1, [1, 2], ([3, 4], 5)]»
# On the other hand, the "single argument rule" slurpy follows the "single argument
# rule" which dictates how to handle the slurpy argument based upon context and
# roughly states that if only a single argument is passed and that argument is
# Iterable, that argument is used to fill the slurpy parameter array. In any
# other case, `+@` works like `**@`.
sub c(+@arr) { @arr.perl.say };
c(['a', 'b', 'c']); # OUTPUT: «["a", "b", "c"]»
c(1, $('d', 'e', 'f'), [2, 3]); # OUTPUT: «[1, ("d", "e", "f"), [2, 3]]»
c(1, [1, 2], ([3, 4], 5)); # OUTPUT: «[1, [1, 2], ([3, 4], 5)]»
# You can call a function with an array using the "argument list flattening"
# operator `|` (it's not actually the only role of this operator,
# but it's one of them).
sub concat3($a, $b, $c) {
say "$a, $b, $c";
}
concat3(|@array); # OUTPUT: «a, b, c»
# `@array` got "flattened" as a part of the argument list
####################################################
# 3. Containers
####################################################
# In Raku, values are actually stored in "containers". The assignment
# operator asks the container on the left to store the value on its right.
# When passed around, containers are marked as immutable which means that,
# in a function, you'll get an error if you try to mutate one of your
# arguments. If you really need to, you can ask for a mutable container by
# using the `is rw` trait.
sub mutate( $n is rw ) {
$n++; # postfix ++ operator increments its argument but returns its old value
}
my $m = 42;
mutate $m; #=> 42, the value is incremented but the old value is returned
say $m; # OUTPUT: «43»
# This works because we are passing the container $m to the `mutate` sub.
# If we try to just pass a number instead of passing a variable, it won't work
# because there is no container being passed and integers are immutable by
# themselves:
# mutate 42; # Parameter '$n' expected a writable container, but got Int value
# Similar error would be obtained, if a bound variable is passed to
# to the subroutine. In Raku, you bind a value to a variable using the binding
# operator `:=`.
my $v := 50; # binding 50 to the variable $v
# mutate $v; # Parameter '$n' expected a writable container, but got Int value
# If what you want is a copy instead, use the `is copy` trait which will
# cause the argument to be copied and allow you to modify the argument
# inside the routine without modifying the passed argument.
# A sub itself returns a container, which means it can be marked as `rw`.
# Alternatively, you can explicitly mark the returned container as mutable
# by using `return-rw` instead of `return`.
my $x = 42;
my $y = 45;
sub x-store is rw { $x }
sub y-store { return-rw $y }
# In this case, the parentheses are mandatory or else Raku thinks that
# `x-store` and `y-store` are identifiers.
x-store() = 52;
y-store() *= 2;
say $x; # OUTPUT: «52»
say $y; # OUTPUT: «90»
####################################################
# 4.Control Flow Structures
####################################################
#
# 4.1 if/if-else/if-elsif-else/unless
#
# Before talking about `if`, we need to know which values are "truthy"
# (represent `True`), and which are "falsey" (represent `False`). Only these
# values are falsey: 0, (), {}, "", Nil, a type (like `Str`, `Int`, etc.) and
# of course, `False` itself. Any other value is truthy.
my $number = 5;
if $number < 5 {
say "Number is less than 5"
}
elsif $number == 5 {
say "Number is equal to 5"
}
else {
say "Number is greater than 5"
}
unless False {
say "It's not false!";
}
# `unless` is the equivalent of `if not (X)` which inverts the sense of a
# conditional statement. However, you cannot use `else` or `elsif` with it.
# As you can see, you don't need parentheses around conditions. However, you
# do need the curly braces around the "body" block. For example,
# `if (True) say 'It's true';` doesn't work.
# You can also use their statement modifier (postfix) versions:
say "Quite truthy" if True; # OUTPUT: «Quite truthy»
say "Quite falsey" unless False; # OUTPUT: «Quite falsey»
# The ternary operator (`??..!!`) is structured as follows `condition ??
# expression1 !! expression2` and it returns expression1 if the condition is
# true. Otherwise, it returns expression2.
my $age = 30;
say $age > 18 ?? "You are an adult" !! "You are under 18";
# OUTPUT: «You are an adult»
#
# 4.2 with/with-else/with-orwith-else/without
#
# The `with` statement is like `if`, but it tests for definedness rather than
# truth, and it topicalizes on the condition, much like `given` which will
# be discussed later.
my $s = "raku";
with $s.index("r") { say "Found a at $_" }
orwith $s.index("k") { say "Found c at $_" }
else { say "Didn't find r or k" }
# Similar to `unless` that checks un-truthiness, you can use `without` to
# check for undefined-ness.
my $input01;
without $input01 {
say "No input given."
}
# OUTPUT: «No input given.»
# There are also statement modifier versions for both `with` and `without`.
my $input02 = 'Hello';
say $input02 with $input02; # OUTPUT: «Hello»
say "No input given." without $input02;
#
# 4.3 given/when, or Raku's switch construct
#
=begin comment
`given...when` looks like other languages' `switch`, but is much more
powerful thanks to smart matching and Raku's "topic variable", `$_`.
The topic variable `$_ `contains the default argument of a block, a loop's
current iteration (unless explicitly named), etc.
`given` simply puts its argument into `$_` (like a block would do),
and `when` compares it using the "smart matching" (`~~`) operator.
Since other Raku constructs use this variable (as said before, like `for`,
blocks, `with` statement etc), this means the powerful `when` is not only
applicable along with a `given`, but instead anywhere a `$_` exists.
=end comment
given "foo bar" {
say $_; # OUTPUT: «foo bar»
# Don't worry about smart matching yet. Just know `when` uses it. This is
# equivalent to `if $_ ~~ /foo/`.
when /foo/ {
say "Yay !";
}
# smart matching anything with `True` is `True`, i.e. (`$a ~~ True`)
# so you can also put "normal" conditionals. For example, this `when` is
# equivalent to this `if`: `if $_ ~~ ($_.chars > 50) {...}`
# which means: `if $_.chars > 50 {...}`
when $_.chars > 50 {
say "Quite a long string !";
}
# same as `when *` (using the Whatever Star)
default {
say "Something else"
}
}
#
# 4.4 Looping constructs
#
# The `loop` construct is an infinite loop if you don't pass it arguments, but
# can also be a C-style `for` loop:
loop {
say "This is an infinite loop !";
last;
}
# In the previous example, `last` breaks out of the loop very much
# like the `break` keyword in other languages.
# The `next` keyword skips to the next iteration, like `continue` in other
# languages. Note that you can also use postfix conditionals, loops, etc.
loop (my $i = 0; $i < 5; $i++) {
next if $i == 3;
say "This is a C-style for loop!";
}
# The `for` constructs iterates over a list of elements.
my @odd-array = 1, 3, 5, 7, 9;
# Accessing the array's elements with the topic variable $_.
for @odd-array {
say "I've got $_ !";
}
# Accessing the array's elements with a "pointy block", `->`.
# Here each element is read-only.
for @odd-array -> $variable {
say "I've got $variable !";
}
# Accessing the array's elements with a "doubly pointy block", `<->`.
# Here each element is read-write so mutating `$variable` mutates
# that element in the array.
for @odd-array <-> $variable {
say "I've got $variable !";
}
# As we saw with `given`, a `for` loop's default "current iteration" variable
# is `$_`. That means you can use `when` in a `for`loop just like you were
# able to in a `given`.
for @odd-array {
say "I've got $_";
# This is also allowed. A dot call with no "topic" (receiver) is sent to
# `$_` (topic variable) by default.
.say;
# This is equivalent to the above statement.
$_.say;
}
for @odd-array {
# You can...
next if $_ == 3; # Skip to the next iteration (`continue` in C-like lang.)
redo if $_ == 4; # Re-do iteration, keeping the same topic variable (`$_`)
last if $_ == 5; # Or break out of loop (like `break` in C-like lang.)
}
# The "pointy block" syntax isn't specific to the `for` loop. It's just a way
# to express a block in Raku.
sub long-computation { "Finding factors of large primes" }
if long-computation() -> $result {
say "The result is $result.";
}
####################################################
# 5. Operators
####################################################
=begin comment
Since Perl languages are very much operator-based languages, Raku
operators are actually just funny-looking subroutines, in syntactic
categories, like infix:<+> (addition) or prefix:<!> (bool not).
The categories are:
- "prefix": before (like `!` in `!True`).
- "postfix": after (like `++` in `$a++`).
- "infix": in between (like `*` in `4 * 3`).
- "circumfix": around (like `[`-`]` in `[1, 2]`).
- "post-circumfix": around, after another term (like `{`-`}` in
`%hash{'key'}`)
The associativity and precedence list are explained below.
Alright, you're set to go!
=end comment
#
# 5.1 Equality Checking
#
# `==` is numeric comparison
say 3 == 4; # OUTPUT: «False»
say 3 != 4; # OUTPUT: «True»
# `eq` is string comparison
say 'a' eq 'b'; # OUTPUT: «False»
say 'a' ne 'b'; # OUTPUT: «True», not equal
say 'a' !eq 'b'; # OUTPUT: «True», same as above
# `eqv` is canonical equivalence (or "deep equality")
say (1, 2) eqv (1, 3); # OUTPUT: «False»
say (1, 2) eqv (1, 2); # OUTPUT: «True»
say Int === Int; # OUTPUT: «True»
# `~~` is the smart match operator which aliases the left hand side to $_ and
# then evaluates the right hand side.
# Here are some common comparison semantics:
# String or numeric equality
say 'Foo' ~~ 'Foo'; # OUTPUT: «True», if strings are equal.
say 12.5 ~~ 12.50; # OUTPUT: «True», if numbers are equal.
# Regex - For matching a regular expression against the left side.
# Returns a `Match` object, which evaluates as True if regexp matches.
my $obj = 'abc' ~~ /a/;
say $obj; # OUTPUT: «「a」»
say $obj.WHAT; # OUTPUT: «(Match)»
# Hashes
say 'key' ~~ %hash; # OUTPUT: «True», if key exists in hash.
# Type - Checks if left side "is of type" (can check superclasses and roles).
say 1 ~~ Int; # OUTPUT: «True»
# Smart-matching against a boolean always returns that boolean (and will warn).
say 1 ~~ True; # OUTPUT: «True», smartmatch against True always matches
say False.so ~~ True; # OUTPUT: «True», use .so for truthiness
# General syntax is `$arg ~~ &bool-returning-function;`. For a complete list
# of combinations, refer to the table at:
# https://docs.raku.org/language/operators#index-entry-smartmatch_operator
# Of course, you also use `<`, `<=`, `>`, `>=` for numeric comparison.
# Their string equivalent are also available: `lt`, `le`, `gt`, `ge`.
say 3 > 4; # OUTPUT: «False»
say 3 >= 4; # OUTPUT: «False»
say 3 < 4; # OUTPUT: «True»
say 3 <= 4; # OUTPUT: «True»
say 'a' gt 'b'; # OUTPUT: «False»
say 'a' ge 'b'; # OUTPUT: «False»
say 'a' lt 'b'; # OUTPUT: «True»
say 'a' le 'b'; # OUTPUT: «True»
#
# 5.2 Range constructor
#
say 3 .. 7; # OUTPUT: «3..7», both included.
say 3 ..^ 7; # OUTPUT: «3..^7», exclude right endpoint.
say 3 ^.. 7; # OUTPUT: «3^..7», exclude left endpoint.
say 3 ^..^ 7; # OUTPUT: «3^..^7», exclude both endpoints.
# The range 3 ^.. 7 is similar like 4 .. 7 when we only consider integers.
# But when we consider decimals:
say 3.5 ~~ 4 .. 7; # OUTPUT: «False»
say 3.5 ~~ 3 ^.. 7; # OUTPUT: «True»,
# This is because the range `3 ^.. 7` only excludes anything strictly
# equal to 3. Hence, it contains decimals greater than 3. This could
# mathematically be described as 3.5 ∈ (3,7] or in set notation,
# 3.5 ∈ { x | 3 < x ≤ 7 }.
say 3 ^.. 7 ~~ 4 .. 7; # OUTPUT: «False»
# This also works as a shortcut for `0..^N`:
say ^10; # OUTPUT: «^10», which means 0..^10
# This also allows us to demonstrate that Raku has lazy/infinite arrays,
# using the Whatever Star:
my @natural = 1..*; # 1 to Infinite! Equivalent to `1..Inf`.
# You can pass ranges as subscripts and it'll return an array of results.
say @natural[^10]; # OUTPUT: «1 2 3 4 5 6 7 8 9 10», doesn't run out of memory!
# NOTE: when reading an infinite list, Raku will "reify" the elements
# it needs, then keep them in memory. They won't be calculated more than once.
# It also will never calculate more elements than that are needed.
# An array subscript can also be a closure. It'll be called with the array's
# length as the argument. The following two examples are equivalent:
say join(' ', @array[15..*]); # OUTPUT: «15 16 17 18 19»
say join(' ', @array[-> $n { 15..$n }]); # OUTPUT: «15 16 17 18 19»
# NOTE: if you try to do either of those with an infinite array, you'll
# trigger an infinite loop (your program won't finish).
# You can use that in most places you'd expect, even when assigning to an array:
my @numbers = ^20;
# Here the numbers increase by 6, like an arithmetic sequence; more on the
# sequence (`...`) operator later.
my @seq = 3, 9 ... * > 95; # 3 9 15 21 27 [...] 81 87 93 99;
# In this example, even though the sequence is infinite, only the 15
# needed values will be calculated.
@numbers[5..*] = 3, 9 ... *;
say @numbers; # OUTPUT: «0 1 2 3 4 3 9 15 21 [...] 81 87», only 20 values
#
# 5.3 and (&&), or (||)
#
# Here `and` calls `.Bool` on both 3 and 4 and gets `True` so it returns
# 4 since both are `True`.
say (3 and 4); # OUTPUT: «4», which is truthy.
say (3 and 0); # OUTPUT: «0»
say (0 and 4); # OUTPUT: «0»
# Here `or` calls `.Bool` on `0` and `False` which are both `False`
# so it returns `False` since both are `False`.
say (0 or False); # OUTPUT: «False».
# Both `and` and `or` have tighter versions which also shortcut circuits.
# They're `&&` and `||` respectively.
# `&&` returns the first operand that evaluates to `False`. Otherwise,
# it returns the last operand.
my ($a, $b, $c, $d, $e) = 1, 0, False, True, 'pi';
say $a && $b && $c; # OUTPUT: «0», the first falsey value
say $a && $b && $c; # OUTPUT: «False», the first falsey value
say $a && $d && $e; # OUTPUT: «pi», last operand since everything before is truthy
# `||` returns the first argument that evaluates to `True`.
say $b || $a || $d; # OUTPUT: «1»
say $e || $d || $a; # OUTPUT: «pi»
# And because you're going to want them, you also have compound assignment
# operators:
$a *= 2; # multiply and assignment. Equivalent to $a = $a * 2;
$b %%= 5; # divisible by and assignment. Equivalent to $b = $b %% 2;
$c div= 3; # return divisor and assignment. Equivalent to $c = $c div 3;
$d mod= 4; # return remainder and assignment. Equivalent to $d = $d mod 4;
@array .= sort; # calls the `sort` method and assigns the result back
####################################################
# 6. More on subs!
####################################################
# As we said before, Raku has *really* powerful subs. We're going
# to see a few more key concepts that make them better than in any
# other language :-).
#
# 6.1 Unpacking!
#
# Unpacking is the ability to "extract" arrays and keys
# (AKA "destructuring"). It'll work in `my`s and in parameter lists.
my ($f, $g) = 1, 2;
say $f; # OUTPUT: «1»
my ($, $, $h) = 1, 2, 3; # keep the non-interesting values anonymous (`$`)
say $h; # OUTPUT: «3»
my ($head, *@tail) = 1, 2, 3; # Yes, it's the same as with "slurpy subs"
my (*@small) = 1;
sub unpack_array( @array [$fst, $snd] ) {
say "My first is $fst, my second is $snd! All in all, I'm @array[].";
# (^ remember the `[]` to interpolate the array)
}
unpack_array(@tail);
# OUTPUT: «My first is 2, my second is 3! All in all, I'm 2 3.»
# If you're not using the array itself, you can also keep it anonymous,
# much like a scalar:
sub first-of-array( @ [$fst] ) { $fst }
first-of-array(@small); #=> 1
# However calling `first-of-array(@tail);` will throw an error ("Too many
# positional parameters passed"), which means the `@tail` has too many
# elements.
# You can also use a slurpy parameter. You could keep `*@rest` anonymous
# Here, `@rest` is `(3,)`, since `$fst` holds the `2`. This results
# since the length (.elems) of `@rest` is 1.
sub slurp-in-array(@ [$fst, *@rest]) {
say $fst + @rest.elems;
}
slurp-in-array(@tail); # OUTPUT: «3»
# You could even extract on a slurpy (but it's pretty useless ;-).)
sub fst(*@ [$fst]) { # or simply: `sub fst($fst) { ... }`
say $fst;
}
fst(1); # OUTPUT: «1»
# Calling `fst(1, 2);` will throw an error ("Too many positional parameters
# passed") though. After all, the `fst` sub declares only a single positional
# parameter.
# You can also destructure hashes (and classes, which you'll learn about later).
# The syntax is basically the same as
# `%hash-name (:key($variable-to-store-value-in))`.
# The hash can stay anonymous if you only need the values you extracted.
# In order to call the function, you must supply a hash wither created with
# curly braces or with `%()` (recommended). Alternatively, you can pass
# a variable that contains a hash.
sub key-of( % (:value($val), :qua($qua)) ) {
say "Got value $val, $qua time" ~~
$qua == 1 ?? '' !! 's';
}
my %foo-once = %(value => 'foo', qua => 1);
key-of({value => 'foo', qua => 2}); # OUTPUT: «Got val foo, 2 times.»
key-of(%(value => 'foo', qua => 0)); # OUTPUT: «Got val foo, 0 times.»
key-of(%foo-once); # OUTPUT: «Got val foo, 1 time.»
# The last expression of a sub is returned automatically (though you may
# indicate explicitly by using the `return` keyword, of course):
sub next-index( $n ) {
$n + 1;
}
my $new-n = next-index(3); # $new-n is now 4
# This is true for everything, except for the looping constructs (due to
# performance reasons): there's no reason to build a list if we're just going to
# discard all the results. If you still want to build one, you can use the
# `do` statement prefix or the `gather` prefix, which we'll see later:
sub list-of( $n ) {
do for ^$n { $_ }
}
my @list3 = list-of(3); #=> (0, 1, 2)
#
# 6.2 Lambdas (or anonymous subroutines)
#
# You can create a lambda by using a pointy block (`-> {}`), a
# block (`{}`) or creating a `sub` without a name.
my &lambda1 = -> $argument {
"The argument passed to this lambda is $argument"
}
my &lambda2 = {
"The argument passed to this lambda is $_"
}
my &lambda3 = sub ($argument) {
"The argument passed to this lambda is $argument"
}
# Both pointy blocks and blocks are pretty much the same thing, except that
# the former can take arguments, and that the latter can be mistaken as
# a hash by the parser. That being said, blocks can declare what's known
# as placeholders parameters through the twigils `$^` (for positional
# parameters) and `$:` (for named parameters). More on them later on.
my &mult = { $^numbers * $:times }
say mult 4, :times(6); #=> «24»
# Both pointy blocks and blocks are quite versatile when working with functions
# that accepts other functions such as `map`, `grep`, etc. For example,
# we add 3 to each value of an array using the `map` function with a lambda:
my @nums = 1..4;
my @res1 = map -> $v { $v + 3 }, @nums; # pointy block, explicit parameter
my @res2 = map { $_ + 3 }, @nums; # block using an implicit parameter
my @res3 = map { $^val + 3 }, @nums; # block with placeholder parameter
# A sub (`sub {}`) has different semantics than a block (`{}` or `-> {}`):
# A block doesn't have a "function context" (though it can have arguments),
# which means that if you return from it, you're going to return from the
# parent function.
# Compare:
sub is-in( @array, $elem ) {
say map({ return True if $_ == $elem }, @array);
say 'Hi';
}
# with:
sub truthy-array( @array ) {
say map sub ($i) { $i ?? return True !! return False }, @array;
say 'Hi';
}
# In the `is-in` sub, the block will `return` out of the `is-in` sub once the
# condition evaluates to `True`, the loop won't be run anymore and the
# following statement won't be executed. The last statement is only executed
# if the block never returns.
# On the contrary, the `truthy-array` sub will produce an array of `True` and
# `False`, which will printed, and always execute the last execute statement.
# Thus, the `return` only returns from the anonymous `sub`
# The `anon` declarator can be used to create an anonymous sub from a
# regular subroutine. The regular sub knows its name but its symbol is
# prevented from getting installed in the lexical scope, the method table
# and everywhere else.
my $anon-sum = anon sub summation(*@a) { [+] @a }
say $anon-sum.name; # OUTPUT: «summation»
say $anon-sum(2, 3, 5); # OUTPUT: «10»
#say summation; # Error: Undeclared routine: ...
# You can also use the Whatever Star to create an anonymous subroutine.
# (it'll stop at the furthest operator in the current expression).
# The following is the same as `{$_ + 3 }`, `-> { $a + 3 }`,
# `sub ($a) { $a + 3 }`, or even `{$^a + 3}` (more on this later).
my @arrayplus3v0 = map * + 3, @nums;
# The following is the same as `-> $a, $b { $a + $b + 3 }`,
# `sub ($a, $b) { $a + $b + 3 }`, or `{ $^a + $^b + 3 }` (more on this later).
my @arrayplus3v1 = map * + * + 3, @nums;
say (*/2)(4); # OUTPUT: «2», immediately execute the Whatever function created.
say ((*+3)/5)(5); # OUTPUT: «1.6», it works even in parens!
# But if you need to have more than one argument (`$_`) in a block (without
# wanting to resort to `-> {}`), you can also either `$^` and `$:` which
# declared placeholder parameters or self-declared positional/named parameters.
say map { $^a + $^b + 3 }, @nums;
# which is equivalent to the following which uses a `sub`:
map sub ($a, $b) { $a + $b + 3 }, @nums;
# Placeholder parameters are sorted lexicographically so the following two
# statements are equivalent:
say sort { $^b <=> $^a }, @nums;
say sort -> $a, $b { $b <=> $a }, @nums;
#
# 6.3 Multiple Dispatch
#
# Raku can decide which variant of a `sub` to call based on the type of the
# arguments, or on arbitrary preconditions, like with a type or `where`:
# with types:
multi sub sayit( Int $n ) { # note the `multi` keyword here
say "Number: $n";
}
multi sayit( Str $s ) { # a multi is a `sub` by default
say "String: $s";
}
sayit "foo"; # OUTPUT: «String: foo»
sayit 25; # OUTPUT: «Number: 25»
sayit True; # fails at *compile time* with "calling 'sayit' will never
# work with arguments of types ..."
# with arbitrary preconditions (remember subsets?):
multi is-big(Int $n where * > 50) { "Yes!" } # using a closure
multi is-big(Int $n where {$_ > 50}) { "Yes!" } # similar to above
multi is-big(Int $ where 10..50) { "Quite." } # Using smart-matching
multi is-big(Int $) { "No" }
subset Even of Int where * %% 2;
multi odd-or-even(Even) { "Even" } # Using the type. We don't name the argument.
multi odd-or-even($) { "Odd" } # "everything else" hence the $ variable
# You can even dispatch based on the presence of positional and named arguments:
multi with-or-without-you($with) {
say "I wish I could but I can't";
}
multi with-or-without-you(:$with) {
say "I can live! Actually, I can't.";
}
multi with-or-without-you {
say "Definitely can't live.";
}
# This is very, very useful for many purposes, like `MAIN` subs (covered
# later), and even the language itself uses it in several places.
# For example, the `is` trait is actually a `multi sub` named `trait_mod:<is>`,
# and it works off that. Thus, `is rw`, is simply a dispatch to a function with
# this signature `sub trait_mod:<is>(Routine $r, :$rw!) {}`
####################################################
# 7. About types...
####################################################
# Raku is gradually typed. This means you can specify the type of your
# variables/arguments/return types, or you can omit the type annotations in
# in which case they'll default to `Any`. Obviously you get access to a few
# base types, like `Int` and `Str`. The constructs for declaring types are
# `subset`, `class`, `role`, etc. which you'll see later.
# For now, let us examine `subset` which is a "sub-type" with additional
# checks. For example, "a very big integer is an `Int` that's greater than 500".
# You can specify the type you're subtyping (by default, `Any`), and add
# additional checks with the `where` clause.
subset VeryBigInteger of Int where * > 500;
# Or the set of the whole numbers:
subset WholeNumber of Int where * >= 0;
my WholeNumber $whole-six = 6; # OK
#my WholeNumber $nonwhole-one = -1; # Error: type check failed...
# Or the set of Positive Even Numbers whose Mod 5 is 1. Notice we're
# using the previously defined WholeNumber subset.
subset PENFO of WholeNumber where { $_ %% 2 and $_ mod 5 == 1 };
my PENFO $yes-penfo = 36; # OK
#my PENFO $no-penfo = 2; # Error: type check failed...
####################################################
# 8. Scoping
####################################################
# In Raku, unlike many scripting languages, (such as Python, Ruby, PHP),
# you must declare your variables before using them. The `my` declarator
# we've used so far uses "lexical scoping". There are a few other declarators,
# (`our`, `state`, ..., ) which we'll see later. This is called
# "lexical scoping", where in inner blocks, you can access variables from
# outer blocks.
my $file_scoped = 'Foo';
sub outer {
my $outer_scoped = 'Bar';
sub inner {
say "$file_scoped $outer_scoped";
}
&inner; # return the function
}
outer()(); # OUTPUT: «Foo Bar»
# As you can see, `$file_scoped` and `$outer_scoped` were captured.
# But if we were to try and use `$outer_scoped` outside the `outer` sub,
# the variable would be undefined (and you'd get a compile time error).
####################################################
# 9. Twigils
####################################################
# There are many special `twigils` (composed sigils) in Raku. Twigils
# define a variable's scope.
# The `*` and `?` twigils work on standard variables:
# * for dynamic variables