├── .gitignore ├── LICENSE ├── PDF └── thinkperl6.pdf ├── Programmation_fonctionnelle_en_Perl_Book ├── Code_samples_chapter_10.txt ├── Code_samples_chapter_2.txt ├── Code_samples_chapter_3.txt ├── Code_samples_chapter_4.txt ├── Code_samples_chapter_5.txt ├── Code_samples_chapter_6.txt ├── Code_samples_chapter_7.txt ├── Code_samples_chapter_8.txt └── Code_samples_chapter_9.txt ├── README.md ├── Supplementary ├── BisectSearch.pm ├── any_lowercase.pl6 ├── calculator.pl6 ├── emma.txt ├── heap2.pl6 ├── json_grammar.pl6 ├── pixel.pl6 └── words.txt └── book ├── Arrays.tex ├── Conditional_and_recursion.tex ├── Fruitful_func.tex ├── Makefile ├── Strings.tex ├── appendix_solutions.tex ├── chapt1.tex ├── chapt_func.tex ├── chapt_var_expr.tex ├── conclusion.tex ├── data_struct_selection.tex ├── figs ├── 450px-International_Morse_Code.svg.png ├── International_Morse_Code.PNG ├── fibonacci.pfi ├── fibonacci.png ├── figure_heap.png ├── figure_heap2.png ├── hash1.pdf ├── hash1.png ├── point2D.png ├── reassignment.pfi ├── reassignment.png ├── rectangle.png ├── rectangle2.pdf ├── stack.eps ├── stack.fig ├── stack.pdf ├── stack2.pdf ├── stack2.png ├── stack3.eps ├── stack3.fig ├── stack3.pdf ├── stack_diagram.pdf ├── stack_diagram.png ├── state6.pfi ├── state6.png ├── test_2.png └── test_5.png ├── footer.html ├── functional.tex ├── grammars.tex ├── hashes.tex ├── header.html ├── hevea.sty ├── intro_part_1.tex ├── intro_part_2.tex ├── iteration.tex ├── latexonly.sty ├── latexonly.tex ├── next.png ├── objects.tex ├── preface.tex ├── thinkperl6.tex ├── up.png └── wordplay.tex /.gitignore: -------------------------------------------------------------------------------- 1 | book/*.aux 2 | book/*.idx 3 | book/*.log 4 | book/*.out 5 | book/*.synctex.gz 6 | book/*.toc 7 | book/*.pdf 8 | book/tmpDir/* 9 | book/*.ind 10 | book/*.ilg 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | License: Creative Commons Attribution-NonCommercial 3.0 Unported License. 2 | (http://creativecommons.org/licenses/by-nc/3.0/) 3 | 4 | Copyright (c) 2017 Allen Downey, Laurent Rosenfeld 5 | 6 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 7 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 8 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 9 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 10 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 11 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 12 | SOFTWARE. 13 | -------------------------------------------------------------------------------- /PDF/thinkperl6.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LaurentRosenfeld/thinkperl6/8223c17d3437475e4e9602699b9348ee53c24c04/PDF/thinkperl6.pdf -------------------------------------------------------------------------------- /Programmation_fonctionnelle_en_Perl_Book/Code_samples_chapter_10.txt: -------------------------------------------------------------------------------- 1 | 2 | ### Scripts pour le livre Programmation fonctionnelle en Perl 3 | Copyright (c) 2018 Laurent Rosenfeld 4 | These code snippets are free software and can be redistributed and/or modified under the same terms as Perl itself. 5 | __________________ 6 | 7 | # Chapitre 10 8 | 9 | __________________ 10 | 11 | # 10. Implanter les fonctions gather et take de Perl 6 12 | 13 | use strict; 14 | use warnings; 15 | 16 | { 17 | my @result; 18 | 19 | sub gather(&) { 20 | my $code_ref = shift; 21 | @result = (); 22 | $code_ref->(); 23 | return @result; 24 | } 25 | 26 | sub take(@) { 27 | my @caller = caller 2; 28 | die "Appel à take hors d'un bloc gather" 29 | unless $caller[3] =~ /gather/; 30 | push @result, @_; 31 | return scalar @result; 32 | } 33 | } 34 | 35 | __________________ 36 | 37 | # 10.2. Exemples d'utilisation simple 38 | 39 | print join " ", gather { take $_ * 2 for (1..10) }; 40 | 41 | __________________ 42 | 43 | print join " ", gather {$_ % 2 and take $_ 44 | for (1..10)}; 45 | # imprime 1 3 5 7 9 46 | __________________ 47 | 48 | print join " ", gather {$_ % 2 and take $_ ** 3 for (1..10)}; 49 | # imprime 1 27 125 343 729 50 | 51 | __________________ 52 | 53 | # 10.3. Gather et take pour construire une fonction my_map 54 | 55 | sub my_map (&@) { 56 | my $coderef = shift; 57 | my @list = @_; 58 | return gather { 59 | take $coderef->($_) for @list; 60 | }; 61 | } 62 | 63 | print join " ", my_map {$_ * 2} 1..10; 64 | print "\n"; 65 | 66 | __________________ 67 | 68 | #10.4. ...Ou my_grep 69 | 70 | sub my_grep (&@) { 71 | my $coderef = shift; 72 | my @list = @_; 73 | return gather { 74 | $coderef->($_) and take $_ for @list; 75 | }; 76 | } 77 | 78 | print join " ", my_grep {$_ % 2} 1..20; 79 | 80 | __________________ 81 | 82 | sub grep_and_map { 83 | my $coderef_grep = shift; 84 | my $coderef_map = shift; 85 | my @list = @_; 86 | return gather { 87 | $coderef_grep->($_) and take $coderef_map->($_) 88 | for @list; 89 | }; 90 | } 91 | 92 | print join " ", grep_and_map ( 93 | sub {$_ % 2}, sub {$_ ** 2}, 0..20 94 | ); 95 | # affiche: 1 9 25 49 81 121 169 225 289 361 96 | 97 | -------------------------------------------------------------------------------- /Programmation_fonctionnelle_en_Perl_Book/Code_samples_chapter_2.txt: -------------------------------------------------------------------------------- 1 | ### Scripts pour le livre Programmation fonctionnelle en Perl 2 | Copyright (c) 2018 Laurent Rosenfeld 3 | These code snippets are free software and can be redistributed and/or modified under the same terms as Perl itself. 4 | __________________ 5 | 6 | # Chapitre 2 7 | 8 | __________________ 9 | 10 | # 2.2.1. Enchaînements d'opérateurs 11 | 12 | my @tab_trie = sort map { sprintf '%02d', $_ } 13 | map { $_ * 2, $_ * 3, $_*4 } 14 | 1..5; 15 | 16 | __________________ 17 | 18 | my @tab_trie = map { s/^0//; $_ } 19 | sort map { sprintf '%02d', $_ } 20 | map { $_ * 2, $_ * 3, $_*4 } 21 | 1..5; 22 | 23 | __________________ 24 | 25 | my ($dupl, $prev) = ("", ""); 26 | my @tab_trie = grep { 27 | $dupl = ($_ == $prev ? 0: 1); 28 | $prev = $_; $dupl 29 | } 30 | map { s/^0//g; $_ } 31 | sort map { sprintf '%02d', $_ } 32 | map { $_ * 2, $_ * 3, $_*4 } 1..5; 33 | 34 | __________________ 35 | 36 | print grep { 37 | $dupl = ($_ == $prev ? 0: 1); 38 | $prev = $_; $dupl 39 | } 40 | map { s/^0//g; $_ } 41 | sort map { sprintf '%02d', $_ } 42 | map { $_ * 2, $_ * 3, $_*4 } 1..5; 43 | 44 | __________________ 45 | 46 | print join '-', grep { 47 | $dupl = ($_ == $prev ? 0: 1); 48 | $prev = $_; $dupl 49 | } 50 | map { s/^0//g; $_ } 51 | sort map { sprintf '%02d', $_ } 52 | map { $_ * 2, $_ * 3, $_*4 } 1..5; 53 | 54 | __________________ 55 | 56 | # 2.2.2. Retour sur la fonction sort 57 | 58 | 59 | my @tab_trie = sort { $a <=> $b } 60 | map { $_ * 2, $_ * 3, $_*4 } 1..5; 61 | 62 | __________________ 63 | 64 | print join '-', 65 | grep { $a = $b == $_? 0: 1; $b = $_; $a;} 66 | sort {$a <=> $b} 67 | map { $_ * 2, $_ * 3, $_*4 } 1..5; 68 | 69 | __________________ 70 | 71 | print join "-", 72 | grep { $_ % 2 == 0 && $_ % 3 == 0 } 73 | 1..50; # noter le && au lieu du || 74 | 75 | __________________ 76 | 77 | # 2.3.1. Tri des noms de famille : version naïve 78 | 79 | sub compare { 80 | my $aa = $1 if $a =~ /(\w+)$/; 81 | # extrait le nom de famille du premier nom 82 | my $bb = $1 if $b =~ /(\w+)$/; 83 | # extrait le nom de famille du second nom 84 | return $aa cmp $bb}; 85 | # cmp renvoie la valeur attendue (-1, 0, 1) 86 | } 87 | 88 | my @noms = ('François Hollande', 'Nicolas Sarkozy', 89 | 'François Fillon', 'Jean-Marc Ayrault', 90 | 'Ségolène Royal', 'Brice Hortefeux', 91 | 'Lionel Jospin', 'George W. Bush', 92 | 'Barack Obama', 'Lorie'); 93 | 94 | my @noms_tries = sort {compare($a, $b)} @noms; 95 | print join ' ,', @noms_tries; 96 | 97 | __________________ 98 | 99 | #2.3.2. La transformation de Schwartz 100 | 101 | print map { $_->[0] } 102 | sort { $a->[1] cmp $b->[1] } 103 | map { [$_, /(\S+)$/] } @noms; 104 | __________________ 105 | 106 | # 2.3.3. La transformation de Guttman Rosler 107 | 108 | my @articles = ( 109 | 'Le Figaro; 10/04/2007; titre1', 110 | 'Le Monde; 17/12/2003; titre2', 111 | 'La Dépêche du Midi; 28/02/2012; titre3', 112 | 'Ouest-France; 14/06/2013; titre 4', 113 | 'Le Canard enchaîné; 18/10/2011; titre 5', 114 | 'La Voix du Nord; 14/11/2009; titre 6' 115 | ); 116 | print map {s/^\d{8};//; $_."\n"} 117 | sort 118 | map {my $date = "$3$2$1" if m[;(\d\d)/(\d\d)/(\d{4});]; 119 | "$date;$_";} 120 | @articles; 121 | __________________ 122 | 123 | use strict; 124 | use warnings; 125 | 126 | my @files = map {s/-0(\d)(\.gz)$/-$1$2/; $_} 127 | sort 128 | map { s/-(\d)(\.gz)$/-0$1$2/; $_ } ; 129 | 130 | print $_ for @files; 131 | 132 | __DATA__ 133 | abcd1_abc_123456.abc1a_A.201307290800-0900-0.gz 134 | abcd1_abc_123456.abc1a_A.201307290800-0900-1.gz 135 | abcd1_abc_123456.abc1a_A.201307290800-0900-10.gz 136 | abcd1_abc_123456.abc1a_A.201307290800-0900-11.gz 137 | abcd1_abc_123456.abc1a_A.201307290800-0900-2.gz 138 | abcd1_abc_123456.abc1a_A.201307290800-0900-3.gz 139 | abcd1_abc_123456.abc1a_A.201306290800-0900-0.gz 140 | abcd1_abc_123456.abc1a_A.201306290800-0900-1.gz 141 | abcd1_abc_123456.abc1a_A.201306290800-0900-10.gz 142 | abcd1_abc_123456.abc1a_A.201305290800-0900-11.gz 143 | abcd1_abc_123456.abc1a_A.201308290800-0900-2.gz 144 | abcd1_abc_123456.abc1a_A.201302290800-0900-3.gz 145 | abcd1_abc_123456.abc1a_A.201306290800-1000-1.gz 146 | abcd1_abc_123456.abc1a_A.201306290800-1000-10.gz 147 | abcd1_abc_123456.abc1a_A.201305290800-1000-11.gz 148 | abcd1_abc_123456.abc1a_A.201308290800-1000-2.gz 149 | abcd1_abc_123456.abc1a_A.201302290800-1000-3.gz 150 | 151 | __________________ 152 | 153 | # 2.3.4.2. Une analyse linguistique rudimentaire 154 | 155 | my %mots; 156 | my $phrase = "Maître Corbeau, sur un arbre perché, tenait en son bec un fromage."; 157 | print join "-", split /[,. ]+/, $phrase; 158 | 159 | __________________ 160 | 161 | print map {$mots{$_}, "\t$_\n"} 162 | reverse sort {$mots{$a} <=> $mots{$b}} 163 | keys %mots; 164 | __________________ 165 | 166 | # 2.3.4.3. Analyse d'un texte plus long 167 | 168 | #!/usr/bin/perl 169 | use strict; 170 | use warnings; 171 | 172 | my %mots; 173 | my $texte; 174 | { 175 | local $/ = undef; 176 | $texte = <>; 177 | } 178 | 179 | $mots{$_}++ foreach 180 | map {$_= lc; tr/àâéèêëîôùûç/aaeeeeiouuc/; $_;} 181 | split /[,.:;"?!'\n ]+/, $texte; 182 | 183 | print map {$mots{$_}, "\t$_\n"} 184 | sort {$mots{$b} <=> $mots{$a} || $a cmp $b} 185 | keys %mots; 186 | __________________ 187 | 188 | # 2.3.4.4. Analyse de livres entiers 189 | 190 | $mots{$_}++ foreach 191 | map { $_= lc; tr/àâéèêëïîôùûç/aaeeeeiiouuc/; $_;} 192 | grep {length > 2} 193 | split /[,.:;"?!'\n ]+/, $texte; 194 | __________________ 195 | 196 | 197 | 198 | -------------------------------------------------------------------------------- /Programmation_fonctionnelle_en_Perl_Book/Code_samples_chapter_3.txt: -------------------------------------------------------------------------------- 1 | ### Scripts pour le livre Programmation fonctionnelle en Perl 2 | Copyright (c) 2018 Laurent Rosenfeld 3 | These code snippets are free software and can be redistributed and/or modified under the same terms as Perl itself. 4 | __________________ 5 | 6 | # Chapitre 3 7 | 8 | __________________ 9 | 10 | # 3.1.1. Transposition lignes-colonnes 11 | 12 | use strict; 13 | use warnings; 14 | 15 | my @transposed_array; 16 | while () { 17 | print; 18 | my $i; 19 | map {$transposed_array[$i++] .= $_;} split; 20 | } 21 | print join " ", script uni 22 | map {my $count = s/OO/00/g; $count? $count : 0;} 23 | @transposed_array; 24 | 25 | __DATA__ 26 | A1 A2 A3 A4 A5 27 | CC NA OO UV OO 28 | NA OO OO OO CP 29 | TR OO UU RR OO 30 | 31 | __________________ 32 | 33 | $ perl -pe '$i = 0; map {@c[$i++] .= $_;} split; END {print join " ", map {$d = s/OO/00/g; $d ? $d : 0;} @c}' data.txt 34 | 35 | __________________ 36 | 37 | # 3.1.3. Trier un tableau en se basant sur l'ordre de tri d'un autre tableau 38 | 39 | my @noms = qw (marie nicolas isabelle yves); 40 | my @salaires = qw (1500 1250 1700 2000); 41 | my %noms_sal; 42 | @noms_sal{@noms} = @salaires; 43 | print map {"$_: $noms_sal{$_} \n"} 44 | sort {$noms_sal{$a} <=> $noms_sal{$b} } 45 | keys %noms_sal; 46 | 47 | __________________ 48 | 49 | # 3.1.4. Un exemple exagéré ? 50 | 51 | while (my $line = <$FILE_IN>) { 52 | my ($start, $end) = split /##/, $line; 53 | my @fields = map { 54 | my ($id, @values) = split /;/, $_; 55 | @values = map { (split /-/, $_)[0]} @values; 56 | map { [$id, $_] } @values; 57 | } split /@/, $end; 58 | my $out_line = $start . "##" . join ";", 59 | map { $_->[0] } 60 | sort { $a->[1] <=> $b->[1] } @fields; 61 | # on peut utiliser $out_line 62 | } 63 | 64 | __________________ 65 | 66 | 67 | while (my $line = <$FILE_IN>) { 68 | my ($start, $end) = split /##/, $line; 69 | my $out_line = $start . "##" . join ";", 70 | map {$_->[0]} 71 | sort {$a->[1] <=> $b->[1]} 72 | map { my ($id, @values) = split /;/, $_; 73 | @values = map { 74 | (split /-/, $_)[0] 75 | } @values; 76 | map { [$id, $_] } @values; 77 | } split /@/, $end; 78 | } 79 | 80 | __________________ 81 | 82 | 83 | # 3.2.1. Un exemple très simple de récursion 84 | 85 | use strict; 86 | use warnings; 87 | use feature "say"; 88 | sub compte_a_rebours { 89 | my $duree_restante = shift; 90 | if ($duree_restante <= 0) { 91 | say "Feu !"; 92 | } else { 93 | say $duree_restante; 94 | compte_a_rebours($duree_restante - 1); 95 | } 96 | } 97 | compte_a_rebours 3; 98 | 99 | __________________ 100 | 101 | use strict; 102 | use warnings; 103 | use feature "say"; 104 | sub compte_a_rebours { 105 | my $duree_restante = shift; 106 | while ($duree_restante > 0) { 107 | say $duree_restante; 108 | $duree_restante--; 109 | } 110 | say "Feu !"; 111 | } 112 | compte_a_rebours 3; 113 | 114 | __________________ 115 | 116 | sub affiche_n_fois { 117 | my ($sentence, $n) = @_; 118 | return if $n <= 0; 119 | say $sentence; 120 | affiche_n_fois($sentence, $n - 1); 121 | } 122 | affiche_n_fois "Bonjour tout le monde", 4; 123 | 124 | __________________ 125 | 126 | # 3.2.2. La fonction factorielle 127 | 128 | __________________ 129 | 130 | sub fact{ 131 | my $n = shift; 132 | if ($n == 0) { 133 | return 1; 134 | } else { 135 | my $recurse = fact($n-1); 136 | my $result = $n * $recurse; 137 | return $result; 138 | } 139 | } 140 | say fact 4; # affiche 24 141 | 142 | __________________ 143 | 144 | # version plus concise et idiomatique 145 | sub fact{ 146 | my $n = shift; 147 | return 1 if $n == 0; 148 | return $n * fact($n-1); 149 | } 150 | say fact 10; # affiche 3628800 151 | 152 | __________________ 153 | 154 | # Version itérative 155 | sub fact{ 156 | my $n = shift; 157 | my $factorielle = 1; 158 | while ($n > 0) { 159 | $factorielle *= $n; 160 | $n --; 161 | } 162 | return $factorielle; 163 | } 164 | say fact 10; # affiche 3628800 165 | 166 | __________________ 167 | 168 | # 3.2.3.1. Fibonacci : mise en œuvre récursive 169 | 170 | # Version de base 171 | use strict; 172 | use warnings; 173 | use feature 'say'; 174 | sub fibo { 175 | my $n = shift; 176 | if ($n < 2) { 177 | return $n; 178 | } else { 179 | return fibo ($n-1) + fibo ($n-2); 180 | } 181 | } 182 | say fibo $_ for 6..8; # Affiche 8, 13, 21 183 | 184 | __________________ 185 | 186 | 187 | # Version avec cache 188 | 189 | use strict; 190 | use warnings; 191 | use feature 'say'; 192 | my @cache = qw /0 1/; # deux valeurs de départ pour 193 | # fibo(0) et fibo(1) 194 | sub fibo { 195 | my $n = shift; 196 | $cache[$n] = fibo($n-1) + fibo($n-2) 197 | unless defined $cache[$n]; 198 | return $cache[$n]; 199 | } 200 | say fibo shift; 201 | 202 | __________________ 203 | 204 | # 3.3.1. Une implémentation non-fonctionnelle du tri fusion 205 | 206 | # Version procédurale ou impérative 207 | use strict; 208 | use warnings; 209 | use feature "say"; 210 | 211 | sub tri_fusion { 212 | my ($out_ref, $a_trier_ref, $start, $end) = @_; 213 | $start = 0 unless defined $start; 214 | $end = scalar @$a_trier_ref unless defined $end; 215 | return if $end - $start < 2; 216 | my $middle = sprintf '%d', ($end + $start) / 2; 217 | tri_fusion($a_trier_ref, $out_ref, 218 | $start, $middle); 219 | tri_fusion($a_trier_ref, $out_ref, $middle, $end); 220 | fusionne_listes($out_ref, $a_trier_ref, 221 | $start, $middle, $end); 222 | } 223 | sub fusionne_listes { 224 | my ($out, $in, $start, $middle, $end) = @_; 225 | my $i = $start; 226 | my $j = $middle; 227 | for my $k ($start..$end - 1) { 228 | if ($i < $middle and 229 | ($j >= $end or $in->[$i] <= $in->[$j])) { 230 | $out->[$k] = $in->[$i]; 231 | $i++; 232 | } else { 233 | $out->[$k] = $in->[$j]; 234 | $j++; 235 | } 236 | } 237 | } 238 | my @array = map { sprintf "%d", rand 100 } 1..15; 239 | my @output = @array; 240 | say "@array"; 241 | tri_fusion \@output, \@array; 242 | say "@output"; 243 | 244 | __________________ 245 | 246 | # 3.3.2. Implémentation fonctionnelle du tri fusion 247 | 248 | use strict; 249 | use warnings; 250 | use feature "say"; 251 | 252 | sub tri_fusion { 253 | my @a_trier = @_; 254 | return @a_trier if @a_trier < 2; 255 | my $middle = sprintf '%d', @a_trier / 2; 256 | my @first = tri_fusion(@a_trier[0 .. $middle - 1]); 257 | my @second = tri_fusion(@a_trier[$middle 258 | .. $#a_trier]); 259 | return fusionne_listes(\@first, \@second); 260 | } 261 | sub fusionne_listes { 262 | my ($un, $deux) = @_; 263 | my @result; 264 | while (1) { 265 | return (@result, @$deux) unless @$un; 266 | return (@result, @$un) unless @$deux; 267 | push @result, $un->[0] < $deux->[0] ? 268 | shift @$un : shift @$deux; 269 | } 270 | } 271 | my @array = map { sprintf "%d", rand 100 } 1..15; 272 | say "@array"; 273 | my @output = tri_fusion @array; 274 | say "@output"; 275 | 276 | __________________ 277 | 278 | # Version fonctionnelle plus concise 279 | 280 | sub merge_sort { 281 | my @x = @_; 282 | return @x if @x < 2; 283 | my $m = int @x / 2; 284 | my @a = merge_sort(@x[0 .. $m - 1]); 285 | my @b = merge_sort(@x[$m .. $#x]); 286 | for (@x) { 287 | $_ = !@a ? shift @b : !@b ? shift @a 288 | : $a[0] <= $b[0] ? shift @a : shift @b; 289 | } 290 | @x; 291 | } 292 | 293 | __________________ 294 | 295 | # 3.4.1. Version non-fonctionnelle du tri rapide 296 | 297 | use strict; 298 | use warnings; 299 | use feature "say"; 300 | 301 | my @output; 302 | sub swap { 303 | my ($in, $x, $y) = @_; 304 | ($in->[$x], $in->[$y]) = ($in->[$y], $in->[$x]); 305 | } 306 | sub qsort { 307 | my ($left, $right) = @_; 308 | my $pivot = $output[int (($left + $right )/2)]; 309 | my $i = $left; 310 | my $j = $right; 311 | while ($i < $j) { 312 | $i++ while $output[$i] < $pivot; 313 | $j-- while $output[$j] > $pivot; 314 | if ($i <= $j) { 315 | swap \@output, $i, $j; 316 | $i++; 317 | $j--; 318 | } 319 | } 320 | qsort($left, $j) if $left < $j; 321 | qsort($i, $right) if $j < $right; 322 | } 323 | sub tri_rapide { 324 | @output = @_; 325 | qsort(0, $#output) 326 | } 327 | my @array = map { sprintf "%d", rand 100 } 1..15; 328 | say "@array"; 329 | tri_rapide @array; 330 | say "@output"; 331 | 332 | __________________ 333 | 334 | # 3.4.3. Tri rapide fonctionnel en Perl 335 | 336 | sub qs { 337 | my @a = @_; 338 | return @a if @a < 2; 339 | my $p = splice @a, int @a/2, 1; 340 | qs(grep $_ < $p, @a), $p, qs(grep $_ >= $p, @a); 341 | } 342 | 343 | __________________ 344 | 345 | # Version plus concise (possiblement moins performante dans certains cas partioculiers) 346 | 347 | sub qs { 348 | return @_ if @_ < 2; 349 | my ($p, @a) = @_; 350 | qs(grep $_ < $p, @a), $p, qs(grep $_ >= $p, @a); 351 | } 352 | 353 | 354 | -------------------------------------------------------------------------------- /Programmation_fonctionnelle_en_Perl_Book/Code_samples_chapter_4.txt: -------------------------------------------------------------------------------- 1 | ### Scripts pour le livre Programmation fonctionnelle en Perl 2 | Copyright (c) 2018 Laurent Rosenfeld 3 | These code snippets are free software and can be redistributed and/or modified under the same terms as Perl itself. 4 | __________________ 5 | 6 | # Chapitre 4 7 | 8 | __________________ 9 | 10 | # 4.2.1.1. Les références sur des variables scalaires 11 | 12 | #!/usr/bin/perl 13 | use strict; 14 | use warnings; 15 | use feature 'say'; 16 | 17 | my $c = 5; 18 | say $c; # imprime 5 19 | my $c_ref = \$c; # \ prend une référence. $c_ref est une référence vers $c 20 | say $c_ref; # Imprime: SCALAR(0x80359e18), l'adresse mémoire de $c 21 | say $$c_ref; # Imprime la valeur référencée par $c_ref, soit 5 22 | $$c_ref ++; # Incrémente la valeur référencée par $c_ref, ce qui donne 6 23 | say $$c_ref; # imprime 6 24 | say $c; # Imprime 6: le contenu de la variable $c a été modifié par l'incrémentation de $$c_ref. 25 | __________________ 26 | 27 | # 4.2.1.2. Les références sur des variables de tableaux 28 | 29 | my @t = qw / 5 6 7/; 30 | say "@t"; # Imprime 5 6 7 31 | my $t_ref= \@t; # $t_ref est une référence vers le tableau @t 32 | say $t_ref; # Imprime ARRAY(0x80355bb0), l'adresse mémoire de @t 33 | say "@$t_ref"; # Imprime le contenu du tableau référencé par $t_ref, soit 5, 6, 7 34 | $$t_ref[1] = 18; # Modifie la 2e valeur du tableau référencé par $t_ref 35 | say "@$t_ref"; # Imprime 5 18 7 36 | say "@t"; # Le tableau @t a bien été modifié, imprime 5 18 7 37 | 38 | __________________ 39 | 40 | # 4.2.1.3. Benchmark du passage d'arguments à une fonction 41 | 42 | use strict; 43 | use warnings; 44 | use Benchmark; 45 | 46 | my @tableau = 0..100000; 47 | 48 | sub valeur { 49 | my @array = @_; 50 | my $c = $array[10000]; 51 | print $c if $c == 17; 52 | } 53 | sub alias { 54 | my $c = $_[10000]; print $c if $c == 17; 55 | }; 56 | sub reference { 57 | my $a_ref = shift; 58 | my $c = $a_ref->[10000]; 59 | print $c if $c == 17; 60 | } 61 | 62 | timethese ( 10000, { 63 | "valeur" => sub { valeur(@tableau); }, 64 | "alias" => sub { alias(@tableau) }, 65 | "reference" => sub { reference(\@tableau) } 66 | } ); 67 | 68 | __________________ 69 | 70 | # 4.2.1.4. Les références sur des variables anonymes pour créer des structures de données complexes 71 | 72 | my @$d_ref = qw /14 13 12/; # peut aussi s'écrire: my $d_ref = [14, 13, 12]; 73 | my @$e_ref = qw /34 35 36/; # ou: my $e_ref = [34, 35, 36]; 74 | my @f = ($t_ref, $d_ref, $e_ref); # @f est un tableau de refs vers des tableaux 75 | say "@f"; # imprime ARRAY(0x80355bb0) ARRAY(0x80355a30) ARRAY(0x8034f508) 76 | 77 | 78 | __________________ 79 | 80 | say $f[0][1]; # Imprime le deuxième élément du premier tableau, soit 18 81 | say $f[2][0]; # Imprime 34 82 | say $f[2]->[0]; # Notation "fléchée", affiche également 34 83 | my $i_ref = $f[2]; # $i_ref est une nouvelle référence contenant ARRAY(0x8034f508) 84 | say $$i_ref[0]; # affiche encore 34 85 | $f[3][1] = 87; # crée un nouveau tableau dans le AoA et met 89 à l'indice 1 86 | __________________ 87 | 88 | # 4.2.2.1. Les références à des fonctions passées aux opérateurs sort et map 89 | 90 | my @tableau = qw / 1 7 17 12 15 3 10 /; 91 | my @tri_1 = sort @tableau; 92 | print "@tri_1 \n"; # imprime: 1 10 12 15 17 3 7 93 | my @tri_2 = sort {$a <=> $b} @tableau; 94 | print "@tri_2 \n"; # imprime: 1 3 7 10 12 15 17 95 | 96 | __________________ 97 | 98 | 4.2.2.3. Réaliser une fonction de rappel 99 | 100 | sub imprime_fichier { 101 | my $fichier = shift; 102 | print $fichier, "\n"; 103 | } 104 | 105 | sub parcours_dir { 106 | my ($path) = @_; 107 | my @dir_entries = glob("$path/*"); 108 | foreach my $entry (@dir_entries) { 109 | imprime_fichier($entry) if -f $entry; 110 | parcours_dir($entry) if -d $entry; 111 | } 112 | } 113 | 114 | parcours_dir($chemin_de_depart); 115 | 116 | __________________ 117 | 118 | sub imprime_fichier { 119 | my $fichier = shift; 120 | print $fichier, "\n"; 121 | } 122 | my $imprime_fic_ref = \&imprime_fichier; # crée une référence sur la fonction 123 | 124 | __________________ 125 | 126 | sub parcours_dir { 127 | my ($code_ref, $path) = @_; 128 | my @dir_entries = glob("$path/*"); 129 | foreach my $entry (@dir_entries) { 130 | $code_ref->($entry) if -f $entry; 131 | parcours_dir($code_ref, $entry) if -d $entry; 132 | } 133 | } 134 | 135 | __________________ 136 | 137 | 138 | #!/usr/bin/perl 139 | use strict; 140 | use warnings; 141 | 142 | my $dir_depart = $ARGV[0]; 143 | chomp $dir_depart; 144 | 145 | sub imprime_fichier { 146 | my $fichier = shift; 147 | print $fichier, "\n"; 148 | } 149 | my $code_ref = \&imprime_fichier; 150 | # crée une référence sur la fonction 151 | 152 | parcours_dir($code_ref, $dir_depart); 153 | 154 | sub parcours_dir { 155 | my ($code_ref, $path) = @_; 156 | my @dir_entries = glob("$path/*"); 157 | foreach my $entry (@dir_entries) { 158 | $code_ref->($entry) if -f $entry; 159 | parcours_dir($code_ref, $entry) if -d $entry; 160 | } 161 | } 162 | 163 | __________________ 164 | 165 | my $glob_size; 166 | my $code_ref = \&find_total_size; 167 | parcours_dir($code_ref, $dir_depart); 168 | print "Taille totale: $glob_size \n"; 169 | 170 | sub find_total_size { 171 | my $fichier = shift; 172 | my $size = -s $fichier; 173 | print $fichier, ' ', $size, "\n"; 174 | $glob_size += $size; 175 | } 176 | 177 | __________________ 178 | 179 | 180 | # 4.2.2.4. D'autres moyens syntaxiques de prendre des références vers des fonctions 181 | 182 | sub imprime_fichier { 183 | my $fichier = shift; 184 | print $fichier, "\n"; 185 | } 186 | my $imprime_fic_ref = \&imprime_fichier; 187 | parcours_dir($imprime_fic_ref, $dir_depart); 188 | 189 | __________________ 190 | 191 | sub imprime_fichier { 192 | my $fichier = shift; 193 | print $fichier, "\n"; 194 | } 195 | parcours_dir(\&imprime_fichier, $dir_depart); 196 | 197 | __________________ 198 | 199 | my $imprime_fic_ref = sub { 200 | my $fichier = shift; 201 | print $fichier, "\n"; 202 | } 203 | 204 | __________________ 205 | 206 | # 4.2.3. Les tables de distribution 207 | 208 | my ($oper, $rest) = shift, join ' ', @ARGV; 209 | my $stop = 'stop'; 210 | my $force_stop = 'force_stop'; 211 | # ... 212 | if ($oper eq $stop) { 213 | run_stop ($rest); 214 | cleanup(); 215 | } 216 | elsif ($oper eq $force_stop) { 217 | run_force_stop ($rest); 218 | cleanup(); 219 | } 220 | elsif ($oper eq 'start') { 221 | run_start ($rest); 222 | } 223 | elsif ($oper eq 'force_start') { 224 | run_stop ($rest); 225 | cleanup(); 226 | run_start ($rest); 227 | } 228 | # ... 229 | else { 230 | die "Opération $oper inconnue"; 231 | } 232 | 233 | 234 | __________________ 235 | 236 | my %dispatch_table = ( 237 | stop => sub {run_stop($rest); cleanup();}, 238 | force_stop => sub { run_force_stop($rest); 239 | cleanup(); 240 | }, 241 | start => /&run_start(@rest), 242 | force_start => sub { run_stop ($rest); cleanup(); 243 | run_start ($rest); 244 | }, 245 | cleanup => sub {unlink $ENV{$flags}} 246 | ); 247 | 248 | my ($oper, $rest) = shift, join ' ', @ARGV; 249 | if (defined $dispatch_table{$oper}) { 250 | $dispatch_table{$oper}->($rest); 251 | } else { 252 | die "Opération $oper inconnue"; 253 | } 254 | 255 | __________________ 256 | 257 | my %dispatch_table = ( 258 | stop => sub {run_stop($rest); cleanup();}, 259 | force_stop => sub { run_force_stop($rest); 260 | cleanup(); 261 | }, 262 | start => /&run_start(@rest), 263 | force_start => sub { run_stop ($rest); cleanup(); 264 | run_start ($rest); 265 | }, 266 | help => sub { print $help;}, 267 | cleanup => sub {unlink $ENV{$flags}} 268 | ); 269 | 270 | __________________ 271 | 272 | # 4.3.1.3. La solution qui marche : premier exemple de fermeture 273 | 274 | { my $nombre = 0; 275 | sub fournit_carre { 276 | $nombre ++; 277 | return $nombre ** 2; 278 | } 279 | } 280 | 281 | __________________ 282 | 283 | #!/usr/bin/perl 284 | use strict; 285 | use warnings; 286 | use feature "state"; 287 | 288 | my $square = fournit_carre(); 289 | print $square, "\n"; 290 | 291 | my $new_square = fournit_carre(); 292 | print $new_square, "\n"; 293 | 294 | sub fournit_carre { 295 | state $nombre = 0; 296 | return ++$nombre ** 2; 297 | } 298 | 299 | __________________ 300 | 301 | # 4.3.2.2. Une version simplifiée de l'interface d'accès 302 | 303 | package Mon_interface; 304 | use strict; 305 | use warnings; 306 | use Low_level_api; 307 | 308 | our @ISA = qw/Exporter/; 309 | our @EXPORT = qw (init_connection); 310 | our @EXPORT_OK = qw (recherche_objet …); 311 | 312 | my ($error_buff_p, $connexion_id, $transaction_id); 313 | my $init_done = 0; 314 | 315 | sub init_connection { 316 | my ($param1, $param2 …) = @_; 317 | my $ebuf_p = API_create_buff($some_param); 318 | my $connect_id = API_connect($some_other_param …); 319 | my $trans_id = open_transaction($ebuf_p, 320 | $connect_id, $autres_params …); 321 | # quelques autres opérations 322 | ($error_buff_p, $connexion_id, $transaction_id) = ($ebuf_p, $connect_id, $trans_id); 323 | $init_done = 1; 324 | return ($ebuf_p, $connect_id, $trans_id); 325 | } 326 | 327 | sub open_transaction { 328 | my ($ebuf_p, $connect_id, $param1, $param2 …) = @_; 329 | # ...fait quelques petites choses supplémentaires 330 | my $transaction_id = API_create_transaction ($ebuf_p, $connect_id, #various_params...); 331 | # ... fait d'autres petites choses 332 | return $transaction_id; 333 | } 334 | 335 | # ... nombreuses fonctions diverses 336 | 337 | sub recherche_objet { 338 | my $search_string_ref = shift; 339 | die_error ("Appelez d'abord la fonction init_connection\n" unless $init_done); 340 | my $search_struct_p = string_to_struct_convert ($error_buff_p, $search_string_ref); 341 | die_error($search_string) if error_detected($error_buff_p); 342 | my $return_struct_p = API_object_search 343 | ($error_buff_p, $transaction_id, $connexion_id, 344 | $search_struct_p); 345 | die_error (…) if error_detected($error_buff_p); 346 | my $return_string = 347 | struct_to_string_convert($error_buff_p, $return_struct_p); 348 | die_error( $search_string) if error_detected($error_buff_p); 349 | free_memory($_) for ($search_struct_p, $return_struct_p); 350 | return \$return_string; 351 | } 352 | 1; 353 | 354 | __________________ 355 | 356 | use strict; 357 | use warnings; 358 | use Mon_interface; 359 | 360 | chomp @ARGV; 361 | my $config_file = shift; 362 | my %config = read_config($config_file); 363 | #... 364 | # les paramètres $ebuf, $connect_id, $trans_id sont 365 | # en principe inutiles ici, mais sont tout de même 366 | # récupérés au cas où l'on voudrait appeler une 367 | # fonction de l'API de bas niveau 368 | my ($ebuf, $connect_id, $trans_id) = 369 | init_connection($some_params); 370 | # ... 371 | my $search_string = "..."; 372 | my $result_ref = recherche_objet($search_string); 373 | # exploitation de $result_ref, etc. 374 | # ... 375 | 376 | 377 | __________________ 378 | 379 | # 4.3.2.3. Variables globales, variables locales, fonctions globales, fonctions locales… 380 | 381 | { 382 | my ($error_buff_p, $connexion_id, $transaction_id); 383 | my $init_done = 0; 384 | sub get_val {return ($error_buff_p, $connexion_id, 385 | $transaction_id, $init_done);}; 386 | sub set_val { ($error_buff_p, $connexion_id, 387 | $transaction_id, $init_done) = @_;}; 388 | } 389 | 390 | __________________ 391 | 392 | sub recherche_objet { 393 | my $search_string_ref = shift; 394 | my ($error_buff_p, $connexion_id, $transaction_id, 395 | init_done) = get_val(); 396 | die_error ("Appelez d'abord la fonction 397 | init_connection\n" unless $init_done); 398 | # ... 399 | } 400 | 401 | __________________ 402 | 403 | # 4.3.2.4. Fonctions locales ou globales, un exemple plus dépouillé 404 | 405 | use strict; 406 | use warnings; 407 | package Essai_loc_func; 408 | require Exporter; 409 | our @ISA = qw/Exporter/; 410 | our @EXPORT_OK = qw (init read_val); 411 | my ($set_val_ref, $get_val_ref); 412 | { 413 | my $val; 414 | $set_val_ref = sub { $val = shift; }; 415 | $get_val_ref = sub { return $val ; }; 416 | } 417 | sub init { $set_val_ref->(shift); }; 418 | sub read_val { return $get_val_ref->(); }; 419 | 1; 420 | 421 | 422 | __________________ 423 | 424 | use strict; 425 | use warnings; 426 | use Essai_loc_func qw (init read_val) ; 427 | 428 | init(7); 429 | my $ret_val = read_val(); 430 | print $ret_val, "\n"; # imprime 7 431 | 432 | __________________ 433 | 434 | # 4.3.3. Utilisation de fermetures anonymes pour renvoyer des fonctions 435 | 436 | my $set_val_ref; 437 | my $get_val_ref; 438 | { 439 | my $val; 440 | $set_val_ref = sub { 441 | $val = shift; 442 | return sub { return $val ; }; 443 | }; 444 | } 445 | 446 | sub init { 447 | $get_val_ref = $set_val_ref->(shift); 448 | } 449 | sub read_val { return $get_val_ref->(); } 450 | 451 | 452 | __________________ 453 | 454 | my $get_val_ref; 455 | my $set_val_ref = sub { 456 | my $val = shift; 457 | return sub { return $val ; }; 458 | }; 459 | 460 | sub init { $get_val_ref = $set_val_ref->(shift); } 461 | sub read_val { return $get_val_ref->(); } 462 | 463 | __________________ 464 | 465 | sub cree_fermeture { 466 | my $val = shift; 467 | # modifie éventuellement $val 468 | # ... 469 | return sub { 470 | # utilise $val pour générer une valeur $valeur 471 | # ... 472 | return $valeur ; 473 | } 474 | } 475 | my $fonction_ref = 476 | cree_fermeture("some_initial_value"); 477 | # (utilisation possible de $fonction_ref) 478 | 479 | __________________ 480 | 481 | # 4.3.4. Retour sur les itérateurs 482 | 483 | sub cree_fermeture { 484 | my $val = shift; 485 | return sub { return $val += 2;} 486 | } 487 | my $iter_pair = cree_fermeture(0); 488 | my $iter_impair = cree_fermeture(1); 489 | 490 | print $iter_pair->(), " " for 1..5; print "\n"; 491 | print $iter_impair->(), " " for 1..15; print "\n"; 492 | print $iter_pair->(), " " for 1..5; print "\n"; 493 | 494 | __________________ 495 | 496 | sub cree_fermeture { 497 | my $val = shift; 498 | sub { $val += 2;} 499 | } 500 | 501 | __________________ 502 | 503 | # 4.3.5.1. Un itérateur de fichier personnalisé 504 | 505 | sub return_iter_cust { 506 | my $file_in = shift; 507 | my $line; 508 | open my $IN, "<", $file_in or 509 | die "cannot open input file $file_in $!"; 510 | return sub { 511 | my @cust_lines; 512 | $line = <$IN> unless defined $line; 513 | chomp $line; 514 | push @cust_lines, [split /;/, $line]; 515 | while ($line = <$IN>) { 516 | chomp $line; 517 | if ($line =~ /^0;/) { # type de ligne 518 | return \@cust_lines; 519 | } else { 520 | push @cust_lines, [split /;/, $line]; 521 | } 522 | } 523 | } 524 | } 525 | 526 | # création des deux itérateurs sur les fichiers A et V 527 | my $a_iter = return_iter_cust ($file_a); 528 | my $v_iter = return_iter_cust ($file_v); 529 | # utilisation des itérateurs 530 | while (my $full_a_cli_ref = $a_iter->()) { 531 | my $full_v_cli_ref = $v_iter->(); 532 | # ... 533 | } 534 | 535 | __________________ 536 | 537 | # 4.3.5.2. Parcours de deux arbres binaires en parallèle 538 | 539 | #!/usr/bin/perl 540 | use strict; 541 | use warnings; 542 | 543 | my $c = [ 1, [ 2, [ 3, [ 4, 5 ] ] ] ]; 544 | my $d = [ 1, [ [ 2, 3 ], [ 4, 5 ] ] ]; 545 | my $e = [ [ [ [ 1, 2 ], 3 ], 4 ], 5 ]; 546 | sameFringe( $c, $c ); 547 | sameFringe( $c, $d ); 548 | sameFringe( $c, $e ); 549 | 550 | sub sameFringe { 551 | my $next_el1 = create_iterator(shift); 552 | my $next_el2 = create_iterator(shift); 553 | my $match = 1; 554 | while (1) { 555 | my $left = $next_el1->(); 556 | my $right = $next_el2->(); 557 | no warnings 'uninitialized'; 558 | print $left, " ", $right, "\n"; 559 | unless ($left eq $right) {$match = 0 ; last} ; 560 | last unless defined $left; 561 | } 562 | $match ? print "the trees match\n": print "the trees don't match\n"; 563 | } 564 | 565 | sub create_iterator { 566 | my $ref = shift; 567 | my @ref_list; 568 | return sub { 569 | while (ref $ref eq 'ARRAY') { 570 | unshift @ref_list, @$ref; 571 | $ref = shift @ref_list; 572 | } 573 | my $leaf = $ref; 574 | $ref = shift @ref_list; 575 | return $leaf; 576 | } 577 | } 578 | 579 | 580 | 581 | __________________ 582 | 583 | 584 | 4.3.5.3. Un itérateur générique ? 585 | 586 | use strict; 587 | use warnings; 588 | 589 | sub create_iter { 590 | my ($code_string, @rest) = @_; 591 | eval $code_string; 592 | } 593 | 594 | my $fibo1 = create_iter ( 595 | ' return sub {my ($c, $d) = @rest; 596 | my $e = $c + $d; @rest = ($d, $e); 597 | return $e;} 598 | ', 599 | 1, 1); 600 | print "Fibo 1: \n"; 601 | print $fibo1->(), " ", for 1..7; # 602 | 603 | my $fibo2 = create_iter ( 604 | q { 605 | return sub {@rest[0,1] = ($rest[1], $rest[0] + $rest[1]); 606 | return $rest[1];} 607 | }, 608 | 1, 1); 609 | print "\n\nFibo2, premier appel: \n"; 610 | print $fibo2->(), " " for 1..5; 611 | 612 | my $fact = create_iter (<<'EOS' 613 | return sub { $rest[0]++; $rest[1] *= $rest[0];}; 614 | EOS 615 | , 1, 1); 616 | print "\n\nFact: \n"; 617 | print $fact->(), " ", for 1..5; 618 | 619 | print "\n\nFibo2, second appel: \n"; 620 | print $fibo2->(), " " for 1..5; 621 | 622 | my $carres = create_iter ('sub { (++$rest[0])**2 }', 1); 623 | print "\n\nCarres: \n"; 624 | print $carres->(), " " for 1..5; 625 | 626 | 627 | __________________ 628 | 629 | # 4.3.5.4. Une file d'attente (FIFO) et une pile (LIFO) 630 | 631 | use strict; 632 | use warnings; 633 | 634 | sub create_fifo { 635 | my @fifo_arr; 636 | return ( 637 | sub {return shift @fifo_arr;}, 638 | sub {push @fifo_arr, shift;} 639 | ); 640 | } 641 | my ($fifo_get, $fifo_put) = create_fifo (); 642 | $fifo_put->($_) for 1..10; 643 | print $fifo_get->() for 1..5; 644 | print "\n"; 645 | 646 | sub create_lifo { 647 | my @lifo_arr; 648 | return ( 649 | sub {return pop @lifo_arr;}, 650 | sub {push @lifo_arr, shift;} 651 | ); 652 | } 653 | my ($lifo_get, $lifo_put) = create_lifo (); 654 | $lifo_put->($_) for 1..10; 655 | print $lifo_get->() for 1..5; 656 | 657 | __________________ 658 | 659 | # 4.3.5.5. Exemple réel : chargement de hachages de paramétrage 660 | 661 | sub load_params { 662 | my $file_name = shift; 663 | my @files = glob ("$data_path${file_name}*.txt"); 664 | my $file = pop @files; 665 | my %param; 666 | open my $IN, "<", $file 667 | or die "Ouverture impossible de $file $!"; 668 | while (<$IN>) { 669 | chomp; 670 | next if /^\s*$/; 671 | my ($key, $val) = split /;/, $_; 672 | $param{$key} = $val 673 | } 674 | close $IN; 675 | return sub { 676 | my $key = shift; 677 | return unless defined $param{$key}; 678 | return $param{$key}; 679 | } 680 | } 681 | 682 | __________________ 683 | 684 | my $offer_mapping_ref = 685 | load_params("B_mapping_offer-mapping_"); 686 | my $migration_mapping_ref = 687 | load_params("B_mapping_migration-status_"); 688 | 689 | __________________ 690 | 691 | sub load_params { 692 | my $file_name = shift; 693 | my @files = glob ("$data_path${file_name}*.txt"); 694 | my $file = pop @files; 695 | my %param; 696 | open my $IN, "<", $file or die "Ouverture impossible de $file $!"; 697 | while (<$IN>) { 698 | chomp; 699 | next if /^\s*$/; 700 | my ($key, $val) = split /;/, $_; 701 | $param{$key} = $val 702 | } 703 | close $IN; 704 | return %param; 705 | } 706 | 707 | 708 | 709 | __________________ 710 | 711 | # 4.3.5.6. Écrire dans des fichiers multiples (répartir des données) 712 | # Premier exemple d'écriture dans des fichiers multiples 713 | 714 | #!/usr/bin/perl 715 | use strict; 716 | use warnings; 717 | 718 | my ($jour, $mois) = (localtime time)[3, 4]; 719 | my $date = sprintf "%02d%02d", ++$mois, $jour; 720 | my $root_name = "99$date-"; 721 | my $chemin = './RESULT'; 722 | 723 | my $write_od1 = 724 | create_file_writer("$chemin/B$root_name"); 725 | my $write_od2 = 726 | create_file_writer("$chemin/E$root_name"); 727 | my $write_od3 = 728 | create_file_writer("$chemin/H$root_name"); 729 | # fichiers de suppression de BV 730 | my $write_suppr = create_file_writer("$chemin/majmv-"); 731 | 732 | my %dispatch_table = ( 733 | 'COD1' => $write_od1, 734 | 'COD2' => $write_od2, 735 | 'COD3' => $write_od3, 736 | 'SUPP' => $write_suppr 737 | ); 738 | 739 | # note: on aurait pu écrire directement les fonctions 740 | # dans la table: 741 | # $dispatch_table{'COD1'} = 742 | # create_file_writer("$chemin/B$root_name"); 743 | # et ainsi de suite. Nous l'avons laissé en deux étapes 744 | # pour des raisons pédagogiques, afin de rester 745 | # simple et clair. 746 | 747 | my $file_in = "./TMP/CORRECTION_MV.TMP"; 748 | open my $INFILE, "<", $file_in or 749 | die "Ouverture impossible du fichier $file_in -$!"; 750 | while (my $line = <$INFILE>) { 751 | my $plateforme = substr $line, 52, 4; 752 | $dispatch_table{$plateforme}->($line); 753 | } 754 | 755 | sub create_file_writer { 756 | my $root_file_name = shift; 757 | my $line_count = 0; 758 | my (@count_file, $fh); 759 | my $old_dos = ""; 760 | return sub { 761 | my $line = shift; 762 | if ($line_count == 0) { 763 | # cas où il va falloir changer de fichier 764 | my $new_dos = substr $line, 4, 10; 765 | # on ne change de fichier que si c'est 766 | #un nouveau dossier 767 | print $fh and return if 768 | $new_dos eq $old_dos; 769 | close $fh if defined $fh; 770 | @count_file = 771 | incremente_compteur(@count_file); 772 | my $sequence = join '', @count_file; 773 | my $file_name = 774 | "$root_file_name$sequence.txt"; 775 | 776 | open $fh , ">", $file_name or 777 | die "Ne peut ouvrir $file_name$!"; 778 | } 779 | print $fh $line; 780 | $line_count ++; 781 | if ( $line_count >= 19990) { 782 | # max = 20000, mais ne pas dégrouper 783 | $line_count = 0; 784 | $old_dos = substr $line, 4, 10; 785 | } 786 | } 787 | } 788 | 789 | sub incremente_compteur { 790 | # la gestion des numéros de séquence alphabétiques 791 | # n'est pas si simple et mérite une procédure 792 | # séparée, mais ne présente pas d'intérêt 793 | # particulier dans notre exemple 794 | # ... 795 | return @new_counter; 796 | } 797 | 798 | 799 | __________________ 800 | 801 | # Second exemple d'écriture dans des fichiers multiples 802 | my $GB_BACKFILL = "$pwd/BADDEBT-BACKFILL_FILE-GB"; 803 | my $DE_BACKFILL = "$pwd/BADDEBT-BACKFILL_FILE-DE"; 804 | my $FR_BACKFILL = "$pwd/BADDEBT-BACKFILL_FILE-FR"; 805 | my $ES_BACKFILL = "$pwd/BADDEBT-BACKFILL_FILE-ES"; 806 | my $IT_BACKFILL = "$pwd/BADDEBT-BACKFILL_FILE-IT"; 807 | 808 | open (GB_BACKFILL, "> $GB_BACKFILL") or 809 | die "unable to open output file: $!"; 810 | open (DE_BACKFILL, "> $DE_BACKFILL") or 811 | die "unable to open output file: $!"; 812 | open (FR_BACKFILL, "> $FR_BACKFILL") or 813 | die "unable to open output file: $!"; 814 | open (ES_BACKFILL, "> $ES_BACKFILL") or 815 | die "unable to open output file: $!"; 816 | open (IT_BACKFILL, "> $IT_BACKFILL") or 817 | die "unable to open output file: $!"; 818 | 819 | while (my $line=) { 820 | my @row = split (",",$line); 821 | 822 | $date = $row[1]; 823 | $esid = $row[4]; 824 | $amount = $row[5]; 825 | $ppcl_id=$row[8]; 826 | $cur=$row[6]; 827 | $cust_id =$row[9]; 828 | if ($custid) 829 | { 830 | if($ppcl_id == 3) 831 | { 832 | print GB_BACKFILL "$custid|$date|391|$esid|-$amount|$cur|$ppcl_id|8\n "; 833 | } 834 | elsif($ppcl_id==4) 835 | { 836 | print DE_BACKFILL "$custid|$date|391|$esid|-$amount|$cur|$ppcl_id|8\n"; 837 | } 838 | elsif($ppcl_id==5) 839 | { 840 | print FR_BACKFILL "$custid|$date|391|$esid|-$amount|$cur|$ppcl_id|8\n "; 841 | } 842 | elsif ($ppcl_id==44551) 843 | { 844 | print ES_BACKFILL "$custid|$date|391|$esid|-$amount|$cur|$ppcl_id|8\n"; 845 | } 846 | elsif($ppcl_id == 35691) 847 | { 848 | print IT_BACKFILL "$custid|$date|391|$esid|-$amount|$cur|$ppcl_id|8\n "; 849 | } 850 | } 851 | } 852 | 853 | __________________ 854 | 855 | # Première solution proposée (abrégée) 856 | open my $US_BACKFILL, '>', 'usfile.txt' or die "$!"; 857 | open my $CA_BACKFILL, '>', 'cafile.txt' or die "$!"; 858 | open my $BR_BACKFILL, '>', 'brfile.txt' or die "$!"; 859 | # etc. pour les autres fichiers 860 | # ... 861 | 862 | my $BACKFILL = $ppcl_id == 1 ? $US_BACKFILL 863 | : $ppcl_id == 7 ? $CA_BACKFILL 864 | : $ppcl_id == 526970 ? $BR_BACKFILL 865 | # : etc. 866 | : undef 867 | ; 868 | if (defined $BACKFILL) { 869 | print {$BACKFILL} "$custid|$date|391|$esid|-$amount|$cur|$ppcl_id|8\n "; 870 | } 871 | 872 | 873 | __________________ 874 | 875 | # # Première solution proposée (abrégée) 876 | my %BACKFILL; 877 | 878 | open $BACKFILL{1}, '>', 'US_backfill.txt' or die "failed to open 'US_BACKFILL.txt' $!"; 879 | open $BACKFILL{6}, '>', 'JP_BACKFIll.txt' or die "failed to open 'JP_BACKFILL.txt' $!"; 880 | open $BACKFILL{7}, '>', 'CA_backfill.txt' or die "failed to open 'CA_BACKFILL.txt' $!"; 881 | # ... 882 | 883 | # Des accolades sont nécessaires autour du 884 | # descripteur de fichier 885 | print {$BACKFILL{$ppcl_id}} "$custid|$date|391|$esid|-$amount|$cur|$ppcl_id|8\n "; 886 | 887 | __________________ 888 | 889 | # Solution complète 890 | 891 | my %dispatch; 892 | $dispatch{3} = create_func( "$pwd/BADDEBT-BACKFILL_FILE-GB"); 893 | $dispatch{4} = create_func( "$pwd/BADDEBT-BACKFILL_FILE-DE"); 894 | $dispatch{5} = create_func( "$pwd/BADDEBT-BACKFILL_FILE-FR"); 895 | $dispatch{44551} = create_func( "$pwd/BADDEBT-BACKFILL_FILE-ES"); 896 | $dispatch{35691} = create_func( "$pwd/BADDEBT-BACKFILL_FILE-IT"); 897 | 898 | while (my $line = ) { 899 | my ($date, $esid, $amount, $ppcl_id, $cur, $custid) = (split ",", $line)[1,4,5,8,6,9]; 900 | $dispatch{$ppcl_id}->("$custid|$date|391|$esid|$amount|$cur|$ppcl_id|8") if $custid; 901 | } 902 | sub create_func { 903 | open my $FH, ">", $_[0] or die "could not open $_[0] $!"; 904 | return sub { print $FH shift, "\n"; } 905 | } 906 | 907 | 908 | -------------------------------------------------------------------------------- /Programmation_fonctionnelle_en_Perl_Book/Code_samples_chapter_5.txt: -------------------------------------------------------------------------------- 1 | ### Scripts pour le livre Programmation fonctionnelle en Perl 2 | Copyright (c) 2018 Laurent Rosenfeld 3 | These code snippets are free software and can be redistributed and/or modified under the same terms as Perl itself. 4 | __________________ 5 | 6 | # Chapitre 5 7 | 8 | __________________ 9 | 10 | # 5.1.1. Fonction map : premiers essais 11 | 12 | # Version triviale 13 | 14 | print join " ", my_map (sub{$_ * 2}, 1..5); 15 | 16 | sub my_map { 17 | my $code_ref = shift; 18 | return map {$code_ref->($_)} @_; 19 | } 20 | # imprime 2 4 6 8 10 21 | 22 | 23 | __________________ 24 | 25 | print join " ", my_map (sub{$_ * 2}, 1..5); 26 | 27 | sub my_map { 28 | my $code_ref = shift; 29 | my @d ; 30 | while ($_ = shift ) { 31 | push @d, $code_ref->($_); 32 | } 33 | return @d; 34 | } 35 | 36 | __________________ 37 | 38 | print join " ", my_map (sub{$_ * 2}, 1..5); 39 | 40 | sub my_map { 41 | my $code_ref = shift; 42 | my @d ; 43 | push @d, $code_ref->($_) for @_; 44 | return @d; 45 | } 46 | 47 | 48 | __________________ 49 | 50 | my @array = (1, 4, 9); 51 | @array = push_square(@array, 4, 5); 52 | print "@array", "\n"; # imprime 1 4 9 16 25 53 | 54 | sub push_square { 55 | my @valeurs = splice @_, $#_ - 1, 2; # retire et récupère les deux dernières valeurs de @_ 56 | my @array = @_; 57 | $_ = $_ * $_ foreach @valeurs; 58 | push @array, @valeurs; 59 | return @array; 60 | } 61 | 62 | __________________ 63 | 64 | my @array = (1, 4, 9); 65 | push_square(\@array, 4, 5); 66 | print "@array", "\n"; # imprime 1 4 9 16 25 67 | 68 | sub push_square { 69 | my $array_ref = shift; 70 | push @$array_ref, map $_ ** 2, @_; 71 | } 72 | 73 | 74 | __________________ 75 | 76 | sub push_square(\@@); 77 | 78 | my @array = (1, 4, 9); 79 | push_square @array, 4, 5; 80 | print "@array", "\n"; # imprime 1 4 9 16 25 81 | 82 | sub push_square(\@@) { 83 | my $array_ref = shift; 84 | push @$array_ref, map $_ ** 2, @_; 85 | } 86 | __________________ 87 | 88 | sub push_square(\@@) { 89 | my $array_ref = shift; 90 | push @$array_ref, map $_ ** 2, @_; 91 | } 92 | 93 | my @array = (1, 4, 9); 94 | push_square @array, 4, 5; 95 | print "@array", "\n"; # imprime 1 4 9 16 25 96 | 97 | __________________ 98 | 99 | # 5.1.3. Des fonctions my_map et my_grep fonctionnelles 100 | 101 | # version avec proto et sans parenthèse 102 | sub my_map(&@); # le prototype doit être avant l'appel 103 | 104 | my @tableau = 1..5; 105 | 106 | print join " ", my_map {$_ * 2} @tableau; 107 | 108 | sub my_map (&@){ 109 | my $code_ref = shift; 110 | my @d; 111 | push @d, $code_ref->($_) for @_; 112 | return @d; 113 | } 114 | # imprime: 2 4 6 8 10 115 | 116 | __________________ 117 | 118 | # Version fonctionnelle "pure", sans effet de bord 119 | sub my_map(&@); # prototype avant l'appel 120 | 121 | my @tableau = 1..5; 122 | 123 | print "Nouveau tableau: ", 124 | join " ", my_map {++$_} @tableau; 125 | print "\nTableau d'origine: ", "@tableau", "\n"; 126 | 127 | sub my_map (&@){ 128 | my $code_ref = shift; 129 | my @d = @_; 130 | $_ = $code_ref->($_) for @d; 131 | return @d; 132 | } 133 | # imprime: 134 | # Nouveau tableau: 2 3 4 5 6 135 | # Tableau d'origine: 1 2 3 4 5 136 | 137 | __________________ 138 | 139 | sub my_grep (&@) { 140 | my $code_ref = shift; 141 | my @result; 142 | push @result, $code_ref->($_) ? $_: () for @_; 143 | return @result; 144 | } 145 | print join " ", my_grep {not $_ %2} (1..10); 146 | # imprime 2 4 6 8 10 147 | 148 | __________________ 149 | 150 | # 5.2. Écrire une fonction sort originale 151 | 152 | #!/usr/bin/perl 153 | use strict; 154 | use warnings; 155 | 156 | sub comb_sort (&\@) { 157 | my $code_ref = shift; 158 | my $v_ref = shift; 159 | my $max = scalar (@$v_ref); 160 | my $gap = $max; 161 | while (1) { 162 | my $swapped = 0; 163 | $gap = int ($gap / 1.3); 164 | $gap = 1 if $gap < 1; 165 | my $lmax = $max - $gap - 1; 166 | foreach my $i (0..$lmax) { 167 | local ($a, $b) = 168 | ($$v_ref[$i], $$v_ref[$i+$gap]); 169 | ($$v_ref[$i], $$v_ref[$i+$gap], $swapped) = 170 | ($$v_ref[$i+$gap], $$v_ref[$i], 1) 171 | if $code_ref->($a, $b) > 0; 172 | } 173 | last if $gap == 1 and $swapped == 0; 174 | } 175 | } 176 | 177 | my @v; 178 | my $max = 500; 179 | 180 | $v[$_] = int rand(20000) foreach (0..$max); 181 | 182 | comb_sort {$a<=>$b} @v; 183 | print "@v"; 184 | 185 | __________________ 186 | 187 | # 5.3.1. Le générateur d'itérateurs 188 | 189 | my @tableau = 1..5; 190 | my $iterateur = create_iter(@tableau); 191 | for (1..4) { 192 | my $val = $iterateur->(); 193 | print $val, "\n" if defined $val; 194 | } 195 | 196 | sub create_iter { 197 | my @array = @_; 198 | return sub { shift @array} 199 | } 200 | 201 | __________________ 202 | 203 | sub create_iter(\@); # la déclaration avec le prototype 204 | # doit figurer avant l'appel 205 | my @tableau = 1..5; 206 | my $iterateur = create_iter(@tableau); 207 | for (1..4) { 208 | my $val = $iterateur->(); 209 | print $val, "\n" if defined $val; 210 | } 211 | 212 | sub create_iter(\@) { 213 | my $array_ref = shift; 214 | my $index = 0; 215 | return sub { $array_ref->[$index++];} 216 | } 217 | 218 | 219 | __________________ 220 | 221 | # 5.3.2.1. Implémentation de la fonction lazy_map 222 | 223 | sub lazy_map(&$); # prototype avant l'appel 224 | sub create_iter(\@); 225 | 226 | my @tableau = reverse 1..7; 227 | my $iterateur = create_iter(@tableau); 228 | 229 | for (1..5) { 230 | my $val = lazy_map {$_**2} $iterateur; 231 | print "Itération N° $_ : $val \n" if defined $val; 232 | } 233 | 234 | sub lazy_map (&$){ 235 | my ($code_ref, $iter) = @_; 236 | local $_ = $iter->(); # lazy_map travaille sur $_ 237 | # comme map 238 | return unless defined $_; 239 | return $code_ref->(); 240 | } 241 | 242 | sub create_iter(\@) { 243 | my $array_ref = shift; 244 | my $index = 0; 245 | return sub { $array_ref->[$index++];} 246 | } 247 | 248 | __________________ 249 | 250 | # 5.3.2.2. Benchmark des fonctions lazy_map et map 251 | 252 | use strict; 253 | use warnings; 254 | use Benchmark; 255 | 256 | my @tableau = ();# voir plus bas les deux cas; 257 | my $iterateur = create_iter (@tableau); 258 | 259 | sub lazy_map (&$){ 260 | my ($code_ref, $iter) = @_; 261 | local $_ = $iter->(); # lazy_map travaille sur $_ 262 | # comme map 263 | return unless defined $_; 264 | return $code_ref->(); 265 | } 266 | 267 | sub create_iter { 268 | my $array_ref = \@_; 269 | my $index = 0; 270 | return sub { $array_ref->[$index++];} 271 | } 272 | 273 | sub try_map { 274 | my @c = grep {$_ == 15000} map { $_ * 2 } @tableau; 275 | } 276 | sub try_lazy_map { 277 | my $iterateur = create_iter(@tableau); 278 | while (1) { 279 | my $val = lazy_map {$_*2} $iterateur; 280 | last unless defined $val; 281 | last if $val == 15000; 282 | } 283 | } 284 | 285 | timethese ( 1000, { 286 | "map" => sub { try_map(); }, 287 | "lazy_map" => sub { try_lazy_map() }, 288 | } ); 289 | 290 | __________________ 291 | 292 | # 5.4. Une fonction lazy_grep 293 | 294 | my @tableau = reverse 1..10; 295 | my $iterateur = create_iter(@tableau); 296 | 297 | sub lazy_grep (&$){ 298 | my ($code_ref, $iter) = @_; 299 | local $_ = $iter->(); 300 | return unless defined $_; 301 | return $_ if $code_ref->(); 302 | return; 303 | } 304 | for (1..9) { 305 | my $val = lazy_grep {$_%2} $iterateur; 306 | print "Itération N° $_ : $val \n" if defined $val; 307 | } 308 | 309 | __________________ 310 | 311 | sub lazy_grep (&$){ 312 | my ($code_ref, $iter) = @_; 313 | while (1) { 314 | local $_ = $iter->() ; 315 | return unless defined $_; # éviter une boucle 316 | # infinie 317 | return $_ if $code_ref->(); 318 | } 319 | } 320 | 321 | my @tableau = reverse 1..10; 322 | my $iterateur = create_iter(@tableau); 323 | 324 | for my $i (1..8) { 325 | my $val = lazy_grep {$_%2} $iterateur; 326 | print "Itération N° $i : $val \n" if defined $val; 327 | } 328 | 329 | __________________ 330 | 331 | sub create_iter(\@) { 332 | my $array_ref = shift; 333 | my $index = 0; 334 | my $max = $#{$array_ref}; # dernier élément 335 | return sub { 336 | return undef if $index > $max; 337 | \$array_ref->[$index++]; 338 | } 339 | } 340 | 341 | __________________ 342 | 343 | # 5.4.2. Fonctions lazy_grep et lazy_map : versions finales 344 | 345 | sub lazy_grep (&$){ 346 | my ($code_ref, $iter) = @_; 347 | while (1) { 348 | my $iref = $iter->(); 349 | return unless $iref; # sort si tableau épuisé 350 | local $_ = $$iref; 351 | next unless defined $_; 352 | # (reboucle si la valeur n'est pas définie) 353 | return $_ if $code_ref->(); 354 | } 355 | } 356 | 357 | 358 | __________________ 359 | 360 | sub lazy_map (&$) { 361 | my ($code_ref, $iter) = @_; 362 | local $_ = ${$iter->()}; 363 | return unless defined $_; 364 | return $code_ref->(); 365 | } 366 | 367 | __________________ 368 | 369 | # 5.5.1. Consommer et renvoyer deux valeurs à chaque demande 370 | 371 | sub create_iter_n($\@) { 372 | my ($nb_items, $array_ref) = @_; 373 | my $index = 0; 374 | my $max = $#{$array_ref} + 1; 375 | # dernier élément du tableau + 1 376 | # car on teste $index après l'incrémentation 377 | return sub { 378 | my @return_array; 379 | push @return_array, $array_ref->[$index++] 380 | for 1..$nb_items; 381 | return undef if $index > $max; 382 | return @return_array; 383 | } 384 | } 385 | 386 | __________________ 387 | 388 | my @input_array = 1..20; 389 | # itérateur de paires : 390 | my $get_2_items = create_iter_n 2, @input_array; 391 | # itérateur de triplets : 392 | my $get_3_items = create_iter_n 3, @input_array; 393 | # itérateur de quadruplets : 394 | my $get_4_items = create_iter_n 4, @input_array; 395 | 396 | print "\nPaires:\n"; 397 | for (1..7) { 398 | print join " ", grep defined $_, $get_2_items->(); 399 | print "\n"; 400 | } 401 | print "\nTriplets:\n"; 402 | for (1..5) { 403 | print join " ", grep defined $_, $get_3_items->(); 404 | print "\n"; 405 | } 406 | print "\nQuadruplets:\n"; 407 | for (1..10) { 408 | print join " ", grep defined $_, $get_4_items->(); 409 | print "\n"; 410 | } 411 | 412 | __________________ 413 | 414 | # 5.5.2. Consommer une valeur et en renvoyer deux (ou plus) 415 | 416 | use strict; 417 | use warnings; 418 | 419 | sub create_iter_1_2(\@) { 420 | my $array_ref = shift; 421 | my $index = 0; 422 | my $max = $#{$array_ref} + 1; 423 | return sub { 424 | return undef if $index > $max; 425 | return ($array_ref->[$index++], 426 | $array_ref->[$index]); 427 | } 428 | } 429 | 430 | my @input_array = (1..5, 7, 11, 18, 34..39); 431 | my $get_2_items = create_iter_1_2 @input_array; 432 | 433 | while (1) { 434 | my ($c, $d) = $get_2_items->(); 435 | last unless defined $d; 436 | print "$c $d\n" and last if $d - $c > 5; 437 | } 438 | 439 | -------------------------------------------------------------------------------- /Programmation_fonctionnelle_en_Perl_Book/Code_samples_chapter_6.txt: -------------------------------------------------------------------------------- 1 | 2 | ### Scripts pour le livre Programmation fonctionnelle en Perl 3 | Copyright (c) 2018 Laurent Rosenfeld 4 | These code snippets are free software and can be redistributed and/or modified under the same terms as Perl itself. 5 | __________________ 6 | 7 | # Chapitre 6 8 | 9 | __________________ 10 | 11 | # 6.1. Expression du besoin 12 | 13 | sub max { 14 | my $max = shift; # initialise $max au 15 | # 1er élément du tableau 16 | for (@_) { $max = $_ if $_ > $max; }; 17 | return $max; 18 | } 19 | 20 | sub min { 21 | my $min = shift; 22 | for (@_) { $min = $_ if $_ < $min; }; 23 | return $min; 24 | } 25 | 26 | sub somme { 27 | my $sum = shift; 28 | for (@_) { $sum += $_; }; 29 | return $sum; 30 | } 31 | 32 | 33 | __________________ 34 | 35 | # 6.1.1. Essais avec une fonction de rappel 36 | 37 | use strict; 38 | use warnings; 39 | 40 | my @c = 1..10; 41 | my $sum_ref = sub { 42 | my $value = shift; 43 | for (@_) { $value += $_; }; 44 | return $value; 45 | }; 46 | my $somme = traite($sum_ref, @c); 47 | 48 | sub traite { 49 | my $code_ref = shift; 50 | return $code_ref->(@_); 51 | } 52 | print "\n $somme \n"; 53 | 54 | 55 | __________________ 56 | 57 | # 6.1.2. Un générateur de fermetures anonymes 58 | 59 | use strict; 60 | use warnings; 61 | 62 | my @c = 1..10; 63 | my $somme = sum(@c); 64 | 65 | sub traite { 66 | my $code_ref = shift; 67 | local $a = $code_ref->($_) for @_; 68 | return $a; 69 | } 70 | 71 | sub sum { 72 | return traite (sub { $a += $_ }, @_); 73 | } 74 | print "\n $somme \n"; 75 | __________________ 76 | 77 | 6.2. La fonction reduce, première version 78 | 79 | sub reduce(&@) { 80 | my $code_ref = shift; 81 | my $result = shift; 82 | $result = $code_ref->($result, $_) for @_; 83 | return $result; 84 | } 85 | 86 | my $max = reduce { 87 | my ($result, $new_val) = @_; 88 | return $result if $result > $new_val; 89 | return $new_val; 90 | } @tableau; 91 | 92 | __________________ 93 | 94 | my $max = reduce {$_[0] > $_[1] ? $_[0] : $_[1]} 1..20; 95 | my $min = reduce {$_[0] > $_[1] ? $_[1] : $_[0]} 1..20; 96 | my $sum = reduce {$_[0] + $_[1]} 1..20; 97 | 98 | __________________ 99 | 100 | sub max { reduce {$_[0] > $_[1] ? $_[0] : $_[1]} @_} 101 | sub min { reduce {$_[0] > $_[1] ? $_[1] : $_[0]} @_} 102 | sub sum { reduce {$_[0] + $_[1]} @_} 103 | 104 | __________________ 105 | 106 | # 6.3.1. Code de la nouvelle version de reduce 107 | 108 | sub reduce (&@) { 109 | my $code_ref = shift; 110 | my $result = shift; 111 | for (@_ ) { 112 | local ($a, $b) = ($result, $_ ); 113 | $result = $code_ref->($a, $b ) 114 | } 115 | return $result; 116 | } 117 | 118 | my $max = reduce { $a > $b ? $a : $b } @_; 119 | _________________ 120 | 121 | # 6.3.2. Le problème de la liste vide 122 | 123 | my @a = 1..10; 124 | print join " ", max(@a), sum(@a); 125 | 126 | sub max { reduce { $a > $b ? $a : $b } @_; } 127 | sub sum { reduce { $a + $b } @_; } 128 | __________________ 129 | 130 | my @a = (); 131 | my $maximum = max(@a); 132 | print $maximum, "\n" if defined $maximum; 133 | 134 | sub max { reduce { $a > $b ? $a : $b } @_; } 135 | 136 | __________________ 137 | 138 | sub sum { 139 | return 0 unless scalar @_; 140 | reduce { $a + $b } @_; 141 | } 142 | 143 | __________________ 144 | 145 | my @a = (); 146 | print sum(@a); 147 | 148 | sub sum { reduce { $a + $b } 0, @_; } 149 | __________________ 150 | 151 | my $nr_elmnts = count (reverse 1..10); 152 | print "$nr_elmnts \n"; 153 | 154 | sub count { reduce { $a + 1 } 0, @_; }; 155 | 156 | __________________ 157 | 158 | # 6.4.1. Fonctions de listes simples 159 | 160 | sub max { 161 | reduce { $a > $b ? $a : $b } @_; 162 | } 163 | sub min { 164 | reduce { $a > $b ? $b : $a } @_; 165 | } 166 | sub sum { 167 | reduce { $a + $b } 0, @_; 168 | } 169 | sub product { 170 | reduce { $a * $b } @_; 171 | } 172 | sub avg { # moyenne 173 | return undef unless @_; # éviter une division par 0 174 | sum (@_)/scalar @_; 175 | } 176 | sub variance { 177 | return undef unless @_; # éviter une division par 0 178 | my $moyenne = avg (@_); 179 | sum ( map {($_ - $moyenne)**2} @_ )/ scalar @_; 180 | # cette dernière ligne pourrait s'écrire plus 181 | # simplement: avg ( map {($_ - $moyenne)**2} @_ ); 182 | } 183 | sub std_dev { # écart-type 184 | sqrt variance (@_); 185 | } 186 | sub maxstr { 187 | reduce { $a gt $b ? $a : $b } @_; 188 | } 189 | sub minstr { 190 | reduce { $a gt $b ? $b : $a } @_; 191 | } 192 | sub longest_str { 193 | reduce { length $a > length $b ? $a : $b } @_; 194 | } 195 | sub shortest_str { 196 | reduce { length $a > length $b ? $b : $a } @_; 197 | } 198 | sub concatenate { 199 | return reduce { $a . $b } @_; 200 | # si l'on préfère considérer que la concaténation 201 | # d'une liste vide est une chaîne vide, mettre: 202 | # return reduce { $a . $b } "", @_; 203 | } 204 | __________________ 205 | 206 | # 6.4.2. Fonctions de listes composées 207 | 208 | sub any { 209 | my $code_ref = shift; 210 | reduce { $a or $code_ref->(local $_ = $b) } @_; 211 | } 212 | sub all { 213 | my $code_ref = shift; 214 | reduce { $a and $code_ref->(local $_ = $b) } @_; 215 | } 216 | sub none { 217 | my $code_ref = shift; 218 | reduce { $a and not $code_ref->(local $_ = $b) } 219 | @_; 220 | } 221 | sub notall { 222 | my $code_ref = shift; 223 | reduce { $a or not $code_ref->(local $_ = $b) } @_; 224 | } 225 | 226 | __________________ 227 | 228 | sub any(&@) { 229 | my $code_ref = shift; 230 | reduce { $a or $code_ref->(local $_ = $b) } 0, @_; 231 | } 232 | sub all(&@) { 233 | my $code_ref = shift; 234 | reduce { $a and $code_ref->(local $_ = $b) } 1, @_; 235 | } 236 | sub none(&@) { 237 | my $code_ref = shift; 238 | reduce { $a and not $code_ref->(local $_ = $b) } 239 | 1, @_; 240 | } 241 | sub notall(&@) { 242 | my $code_ref = shift; 243 | reduce { $a or not $code_ref->(local $_ = $b) } 244 | 0, @_; 245 | } 246 | 247 | -------------------------------------------------------------------------------- /Programmation_fonctionnelle_en_Perl_Book/Code_samples_chapter_7.txt: -------------------------------------------------------------------------------- 1 | 2 | ### Scripts pour le livre Programmation fonctionnelle en Perl 3 | Copyright (c) 2018 Laurent Rosenfeld 4 | These code snippets are free software and can be redistributed and/or modified under the same terms as Perl itself. 5 | __________________ 6 | 7 | # Chapitre 7 8 | 9 | __________________ 10 | 11 | #7.1. Afficher une trace des appels à une fonction 12 | 13 | use strict; 14 | use warnings; 15 | use feature 'say'; 16 | 17 | affiche_la_reponse(); 18 | 19 | sub affiche_la_reponse { 20 | say "42"; 21 | } 22 | 23 | 24 | __________________ 25 | 26 | my $count = 0; 27 | sub trace_appels { 28 | $count++; 29 | say "Appel numéro $count de la fonction surveillée"; 30 | affiche_la_reponse(); 31 | } 32 | trace_appels() for 1..3; 33 | 34 | __________________ 35 | 36 | my $count = 0; 37 | sub enrichit { 38 | my $fonction = shift; 39 | $count++; 40 | say "Appel numéro $count de la fonction surveillée"; 41 | $fonction->(); 42 | } 43 | enrichit(\&affiche_la_reponse) for 1..3; 44 | __________________ 45 | 46 | sub enrichit { 47 | my $fonction = shift; 48 | $count++; 49 | say "Appel numéro $count de la fonction surveillée"; 50 | $fonction->(@_); 51 | } 52 | enrichit(\&fonction_surveillee, $param1, $param2); 53 | 54 | __________________ 55 | 56 | # 7.2. Créer la fonction décoratrice 57 | 58 | use strict; 59 | use warnings; 60 | use feature 'say'; 61 | 62 | sub triplement { 63 | return 3 * shift; 64 | } 65 | 66 | my $triplement_decore = decorateur(\&triplement); 67 | say $triplement_decore->($_) for 10, 15, 20; 68 | 69 | sub decorateur { 70 | my $coderef = shift; 71 | return sub { 72 | say "Appel de la fonction avec les arguments: @_"; 73 | my $resultat = $coderef->(@_); 74 | say "Valeur de retour: $resultat."; 75 | return $resultat; 76 | } 77 | } 78 | __________________ 79 | 80 | # 7.2.1. Enrichir le décorateur 81 | 82 | sub decorateur { 83 | my $coderef = shift; 84 | my $num_appel = 1; 85 | return sub { 86 | say "Appel numéro $num_appel de la fonction avec les arguments: @_"; 87 | $num_appel++; 88 | my $resultat = $coderef->(@_); 89 | say "Valeur de retour: $resultat."; 90 | return $resultat; 91 | } 92 | } 93 | 94 | __________________ 95 | 96 | # 7.2.2. Décorateur en contexte scalaire ou de liste ? 97 | 98 | sub multiplie234 { 99 | return $_[0] * 2, $_[0] * 3, $_[0] * 4; 100 | } 101 | 102 | my $multiplie_decore = decorateur(\&multiplie234); 103 | say $_ for $multiplie_decore->(20); 104 | 105 | sub decorateur { 106 | my $coderef = shift; 107 | my $num_appel = 1; 108 | return sub { 109 | say "Appel numéro $num_appel de la fonction avec les arguments: @_"; 110 | $num_appel++; 111 | my @resultat = $coderef->(@_); 112 | say "Valeurs de retour: @resultat."; 113 | return @resultat; 114 | } 115 | } 116 | 117 | __________________ 118 | 119 | my $multiplie_decore = decorateur(\&multiplie234); 120 | say $_ for $multiplie_decore->(20); 121 | my $triplement_decore = decorateur(\&triplement); 122 | say $triplement_decore->($_) for 5, 10, 15; 123 | 124 | __________________ 125 | 126 | # 7.2.3.1. Et hop, un petit tour de magie blanche 127 | 128 | *main::triplement = decorateur(\&triplement); 129 | say triplement($_) for 10, 15; 130 | 131 | __________________ 132 | 133 | 7.2.3.4. Suppression de l'avertissement de redéfinition 134 | 135 | { 136 | no warnings 'redefine'; 137 | *main::triplement = decorateur(\&triplement); 138 | } 139 | say triplement($_) for 15, 30; 140 | __________________ 141 | 142 | # 7.2.3.5. La table des symboles d'un module particulier 143 | 144 | #!/usr/bin/perl 145 | 146 | package Multiplie; 147 | 148 | use strict; 149 | use warnings; 150 | 151 | require Exporter; 152 | our @ISA = qw/Exporter/; 153 | our @EXPORT = qw (quadruplement); 154 | 155 | sub quadruplement { 156 | return 4 * shift; 157 | }; 158 | # ... autres fonctions éventuelles 159 | 1; 160 | __________________ 161 | 162 | #!/usr/bin/perl 163 | 164 | use strict; 165 | use warnings; 166 | use feature 'say'; 167 | use Multiplie; 168 | 169 | say quadruplement($_) for 5, 15; 170 | __________________ 171 | 172 | { 173 | no warnings 'redefine'; 174 | *{Multiplie::quadruplement} = decorateur(\&quadruplement); 175 | } 176 | 177 | sub quadruplement { 178 | return 4 * shift; 179 | }; 180 | 181 | sub decorateur { 182 | my $coderef = shift; 183 | my $num_appel = 1; 184 | return sub { 185 | say "Appel n° $num_appel de la fonction avec les arguments: @_"; 186 | $num_appel++; 187 | my $resultat = $coderef->(@_); 188 | say "Valeur de retour: $resultat."; 189 | return $resultat; 190 | } 191 | } 192 | __________________ 193 | 194 | { 195 | no warnings 'redefine'; 196 | no strict 'refs'; 197 | *{__PACKAGE__ . "::quadruplement"} = decorateur(\&quadruplement); 198 | } 199 | 200 | __________________ 201 | 202 | { 203 | no warnings 'redefine'; 204 | *main::quadruplement = decorateur(\&quadruplement); 205 | } 206 | 207 | say quadruplement($_) for 5, 15; 208 | 209 | 210 | sub decorateur { 211 | my $coderef = shift; 212 | my $num_appel = 1; 213 | return sub { 214 | say "Appel numéro $num_appel de la fonction avec les arguments: @_"; 215 | $num_appel++; 216 | my $resultat = $coderef->(@_); 217 | say "Valeur de retour: $resultat."; 218 | return $resultat; 219 | } 220 | } 221 | __________________ 222 | 223 | # 7.2.4. Automatiser l'installation du décorateur 224 | 225 | sub decore { 226 | my ($sub_name, $decorator) = @_; 227 | no warnings 'redefine'; 228 | no strict 'refs'; 229 | *{"main::$sub_name"} = $decorator->(\&{$sub_name}); 230 | } 231 | # Mettre en place la décoration est maintenant simple: 232 | decore ("triplement", \&decorateur); 233 | say triplement($_) for 15, 30; 234 | 235 | 236 | __________________ 237 | 238 | # 7.3. Retour à la fonction de Fibonacci 239 | 240 | sub fibo { 241 | my $n = shift; 242 | if ($n < 2) { 243 | return $n; 244 | } else { 245 | return fibo ($n-1) + fibo ($n-2); 246 | } 247 | } 248 | 249 | sub cache { 250 | my $code_ref = shift; 251 | my @memo = (0, 1); 252 | return sub { 253 | my $n = shift; 254 | $memo[$n] = $code_ref->($n) unless defined $memo[$n]; 255 | return $memo[$n]; 256 | } 257 | } 258 | 259 | decore("fibo", \&cache); 260 | say fibo(shift); 261 | 262 | __________________ 263 | 264 | # 7.3.2. Le module memoize 265 | 266 | sub cache { 267 | my $code_ref = shift; 268 | my %memo; 269 | return sub { 270 | my $n = shift; 271 | $memo{$n} = $code_ref->($n) 272 | unless defined $memo{$n}; 273 | return $memo{$n}; 274 | } 275 | } 276 | __________________ 277 | 278 | use strict; 279 | use warnings; 280 | use feature 'say'; 281 | 282 | 283 | sub fibo { 284 | my $n = shift; 285 | return $n if $n < 2; 286 | return fibo ($n-1) + fibo ($n-2); 287 | } 288 | 289 | sub memoize { 290 | my $sub_name = shift; 291 | my %memo; 292 | my $code_ref = \&{$sub_name}; 293 | my $new_func = sub { 294 | my $n = shift; 295 | $memo{$n} = $code_ref->($n) unless defined $memo{$n}; 296 | return $memo{$n}; 297 | }; 298 | no warnings 'redefine'; 299 | no strict 'refs'; 300 | *{"main::$sub_name"} = $new_func; 301 | } 302 | 303 | memoize("fibo"); 304 | say fibo(shift); 305 | 306 | 307 | -------------------------------------------------------------------------------- /Programmation_fonctionnelle_en_Perl_Book/Code_samples_chapter_8.txt: -------------------------------------------------------------------------------- 1 | 2 | ### Scripts pour le livre Programmation fonctionnelle en Perl 3 | Copyright (c) 2018 Laurent Rosenfeld 4 | These code snippets are free software and can be redistributed and/or modified under the same terms as Perl itself. 5 | __________________ 6 | 7 | # Chapitre 8 8 | 9 | __________________ 10 | 11 | # 8.1. L'idée de base de la curryfication 12 | 13 | sub add { 14 | my $ajout = shift; 15 | return sub {$ajout + shift} 16 | }; 17 | my $add_2 = add(2); 18 | print $add_2->(3); # imprime 5 19 | 20 | 21 | __________________ 22 | 23 | # 8.3. Curryfication de la fonction parcours_dir 24 | 25 | #!/usr/bin/perl 26 | use strict; 27 | use warnings; 28 | 29 | sub create_func { 30 | my $code_ref = shift; 31 | my $func; 32 | $func = sub { 33 | my $path = shift; 34 | my @dir_entries = glob("$path/*"); 35 | foreach my $entry (@dir_entries) { 36 | $code_ref->($entry) if -f $entry; 37 | $func->($entry) if -d $entry; 38 | } 39 | } 40 | } 41 | my $print_dir = create_func(sub { print shift, "\n"; }); 42 | $print_dir->($ARGV[0]); 43 | 44 | __________________ 45 | 46 | #!/usr/bin/perl 47 | use strict; 48 | use warnings; 49 | 50 | sub create_func { 51 | my ($code_ref, $tot_size_ref) = @_; 52 | my $func; 53 | $func = sub { 54 | my $path = shift; 55 | my @dir_entries = glob("$path/*"); 56 | foreach my $entry (@dir_entries) { 57 | $func->($entry) and next if -d $entry; 58 | $code_ref->($tot_size_ref, $entry) 59 | if -f $entry; 60 | } 61 | } 62 | } 63 | my $tot_size = 0; 64 | my $size_dir_func_ref = create_func( 65 | sub { 66 | my $size_ref = shift; 67 | $$size_ref += (-s shift) 68 | }, \$tot_size); 69 | $size_dir_func_ref->($ARGV[0]); 70 | print $tot_size, "\n"; 71 | 72 | 73 | __________________ 74 | 75 | #!/usr/bin/perl 76 | use strict; 77 | use warnings; 78 | 79 | sub create_func { 80 | my $code_ref = shift; 81 | my $func; 82 | $func = sub { 83 | my $path = shift; 84 | my @dir_entries = glob("$path/*"); 85 | foreach my $entry (@dir_entries) { 86 | $func->($entry) and next if -d $entry; 87 | $code_ref->($entry) if -f $entry; 88 | } 89 | } 90 | } 91 | 92 | sub parcours_dir { 93 | my $tot_size = 0; 94 | my $size_dir_func_ref = 95 | create_func( sub { $tot_size += (-s shift)} ); 96 | $size_dir_func_ref->($_[0]); 97 | return $tot_size, "\n"; 98 | } 99 | print parcours_dir($ARGV[0]); 100 | 101 | __________________ 102 | 103 | # 8.4. Une version curryfiée de reduce 104 | 105 | use strict; 106 | use warnings; 107 | 108 | sub reduce (&) { 109 | my $code_ref = shift; 110 | my $func = sub { 111 | my $result = shift; 112 | for (@_ ) { 113 | local ($a, $b) = ($result, $_ ); 114 | $result = $code_ref->($a, $b ); 115 | } 116 | return $result; 117 | }; 118 | return $func; 119 | } 120 | 121 | my $max = sub { reduce { $a > $b ? $a : $b } }; 122 | my $maximum = $max->()->(1..10); 123 | print "Le max est: $maximum \n"; 124 | 125 | 126 | __________________ 127 | 128 | sub reduce (&) { 129 | my $code_ref = shift; 130 | return sub { 131 | my $result = shift; 132 | for (@_ ) { 133 | local ($a, $b) = ($result, $_ ); 134 | $result = $code_ref->($a, $b ); 135 | } 136 | return $result; 137 | }; 138 | } 139 | __________________ 140 | 141 | use strict; 142 | use warnings; 143 | 144 | sub reduce (&@) { 145 | my $code_ref = shift; 146 | return sub { 147 | my $result = shift; 148 | for (@_ ) { 149 | local ($a, $b) = ($result, $_ ); 150 | $result = $code_ref->($a, $b ); 151 | } 152 | return $result; 153 | }; 154 | } 155 | *max = reduce { $a > $b ? $a : $b }; 156 | my $maximum = max(1..10); 157 | print "Le max est: $maximum \n"; # imprime "Le max est: 10" 158 | 159 | __________________ 160 | 161 | *max reduce { $a > $b ? $a : $b }; 162 | *min reduce { $a > $b ? $b : $a }; 163 | *product reduce { $a * $b }; 164 | # etc. 165 | 166 | __________________ 167 | 168 | # 8.5. La curryfication automatique 169 | 170 | 171 | use strict; 172 | use warnings; 173 | 174 | sub curry (\&@) { 175 | my $code = shift; 176 | my @args = @_; 177 | sub { 178 | unshift @_, @args; 179 | goto &$code; 180 | }; 181 | } 182 | 183 | my $curried_add = curry(&add, 6); 184 | print $curried_add->(5); # imprime 11 185 | 186 | sub add { 187 | my ($c, $d) = @_; 188 | return $c + $d; 189 | } 190 | __________________ 191 | 192 | sub subtract { 193 | my ($c, $d) = @_; 194 | return $c - $d; 195 | } 196 | 197 | my $curried_subtr = curry(&subtract, 6); 198 | print $curried_subtr->(5); # imprime 1 199 | __________________ 200 | 201 | sub subtract { 202 | my ($c, $d) = @_; 203 | return $d - $c; 204 | } 205 | my $subtract_1 = curry(&subtract, 1); 206 | print $subtract_1->(4); # imprime 3 207 | 208 | __________________ 209 | 210 | # 8.6. Prototypes et curryfication automatique : la fonction comb_sort 211 | 212 | my @v; 213 | my $max = 500; 214 | $v[$_] = int rand(20000) foreach (0..$max); 215 | 216 | my $curried_comb_sort = curry (&comb_sort, sub {$a<=>$b}); 217 | $curried_comb_sort->(\@v); 218 | print "@v"; 219 | 220 | -------------------------------------------------------------------------------- /Programmation_fonctionnelle_en_Perl_Book/Code_samples_chapter_9.txt: -------------------------------------------------------------------------------- 1 | 2 | ### Scripts pour le livre Programmation fonctionnelle en Perl 3 | Copyright (c) 2018 Laurent Rosenfeld 4 | These code snippets are free software and can be redistributed and/or modified under the same terms as Perl itself. 5 | __________________ 6 | 7 | # Chapitre 9 8 | 9 | __________________ 10 | 11 | # 9.1.1. La fonction combine 12 | 13 | sub combine (&\@\@) { 14 | my ($code_ref, $l1_ref, $l2_ref) = @_; 15 | my @result; 16 | while (1) { 17 | local ($a, $b); 18 | ($a, $b) = (shift @$l1_ref, shift @$l2_ref); 19 | return @result unless defined $a 20 | and defined $b; 21 | push @result, $code_ref->($a, $b); 22 | } 23 | } 24 | 25 | sub add2 (\@\@) { 26 | my ($l1, $l2) = @_; 27 | return combine {$a + $b} @$l1, @$l2; 28 | } 29 | 30 | sub avg2(\@\@) { 31 | my ($l1, $l2) = @_; 32 | return combine {($a + $b) /2} @$l1, @$l2; 33 | } 34 | 35 | __________________ 36 | 37 | use strict; 38 | use warnings; 39 | use Combine qw/combine add2/; 40 | 41 | my @list1 = qw /1 5 7 98 32/; 42 | my @list2 = grep $_%2, 1..10; # nombres impairs entre 1 et 10 43 | 44 | print join " ", add2(@list1, @list2), "\n"; 45 | __________________ 46 | 47 | # Version ne modifiant pas les tableaux reçus en arguments 48 | sub combine (&\@\@) { 49 | my ($code_ref, $l1_ref, $l2_ref) = @_; 50 | my @result; 51 | my $i = 0; 52 | while (1) { 53 | local ($a, $b) = 54 | ($l1_ref->[$i], $l2_ref->[$i++]); 55 | return @result unless defined $a and defined $b; 56 | push @result, $code_ref->($a, $b); 57 | } 58 | } 59 | __________________ 60 | 61 | # 9.2. Une fonction intermédiaire de création de fonctions 62 | 63 | sub create_function2 { 64 | my $code_ref = shift; 65 | return sub { 66 | my ($l1_ref, $l2_ref) = @_; 67 | return combine {&$code_ref} @$l1_ref, @$l2_ref; 68 | } 69 | } 70 | 71 | 72 | __________________ 73 | 74 | sub create_function2(&) { 75 | my $code_ref = shift; 76 | return sub { 77 | return combine {&$code_ref} @{$_[0]}, @{$_[1]}; 78 | } 79 | } 80 | __________________ 81 | 82 | my $add2 = create_function2(sub {$a + $b}); 83 | 84 | my @list1 = qw /1 5 7 98 32/; 85 | my @list2 = grep $_%2, 1..10; 86 | 87 | print join " ", $add2->(\@list1, \@list2), "\n"; 88 | 89 | sub create_function2 { 90 | my $code_ref = shift; 91 | sub { combine {&$code_ref} @{$_[0]}, @{$_[1]}; 92 | } 93 | } 94 | 95 | __________________ 96 | 97 | # 9.2.1. Créer une bibliothèque de fonctions 98 | 99 | my $add2 = create_function2( sub { $a + $b } ); 100 | my $avg2 = create_function2( sub {( $a + $b ) / 2 } ); 101 | my $substr2 = create_function2( sub { $a - $b } ); 102 | my $diff2 = create_function2( sub { abs( $a - $b ) } ); 103 | my $mult2 = create_function2( sub { $a * $b } ); 104 | my $eq_nr = create_function2( sub { $a if $a == $b } ); 105 | my $eq_str = create_function2( sub {$a if $a eq $b } ); 106 | my $each_array = create_function2( sub { $a, $b } ); 107 | # ... 108 | 109 | __________________ 110 | 111 | my @list1 = qw /1 32 5 7 98/; 112 | my @list2 = grep $_%2, 1..10; 113 | 114 | print join " ", $add2->(\@list1, \@list2), "\n"; 115 | print join " ", $avg2->(\@list1, \@list2), "\n"; 116 | print join " ", $substr2->(\@list1, \@list2), "\n"; 117 | print join " ", $diff2->(\@list1, \@list2), "\n"; 118 | print join " ", $mult2->(\@list1, \@list2), "\n"; 119 | print join " ", $equal_nr->(\@list1, \@list2), "\n"; 120 | print join " ", $equal_str->(\@list1, \@list2), "\n"; 121 | print join " ", $each_array->(\@list1, \@list2), "\n"; 122 | __________________ 123 | 124 | # 9.2.2. Simplification syntaxique 125 | 126 | sub add2 (\@\@) { 127 | my ($list1, $list2) = @_; 128 | return $add2->(\@list1, \@list2); 129 | } 130 | 131 | my @list1 = qw /1 32 5 7 98/; 132 | my @list2 = grep $_%2, 1..10; 133 | 134 | print join " ", add2(@list1, @list2), "\n"; 135 | 136 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # thinkperl6 2 | 3 | ### Generating the PDF 4 | 5 | The directory `book` contains the LaTeX sources needed to compile the book. 6 | To recompile it, run the following command within the directory: 7 | ``` 8 | make 9 | ``` 10 | This command will create the directory `tmpDir` where you'll find the PDF (thinkperl6.pdf) 11 | alonside other intermediate files created during the compilation process. 12 | 13 | To move the created pdf to the directory `PDF` in the root directory, run: 14 | ``` 15 | make pdf 16 | ``` 17 | 18 | To remove `tmpDir`, run: 19 | ``` 20 | make clean 21 | ``` 22 | **Note**: The chances of a successful compilation increase if you have an almost 23 | complete installation of a recent TeX Live distribution. 24 | 25 | Also note that a PDF version is available (https://github.com/LaurentRosenfeld/thinkperl6/tree/master/PDF). 26 | 27 | There are some Perl 6 examples of this book in the https://github.com/LaurentRosenfeld/thinkperl6/tree/master/Supplementary directory and a quite a bit of additional material on the Perl 6 language (conference talks, blog posts, etc.) in the 28 | https://github.com/LaurentRosenfeld/Perl-6-Miscellaneous directory. 29 | 30 | -------------------------------------------------------------------------------- /Supplementary/BisectSearch.pm: -------------------------------------------------------------------------------- 1 | unit module BisectSearch; 2 | 3 | multi sub bisect (Str $word, @word_list) is export { 4 | sub bisect2 ($low_idx, $high_idx) { 5 | my $mid_idx = (($low_idx + $high_idx) /2).Int; 6 | my $found = @word_list[$mid_idx]; 7 | return $mid_idx if $word eq $found; 8 | return -1 if $low_idx >= $high_idx; 9 | if $word lt $found { 10 | # search the first half 11 | return bisect2 $low_idx, $mid_idx - 1; 12 | } else { 13 | # search the second half 14 | return bisect2 $mid_idx+1, $high_idx; 15 | } 16 | } 17 | my $max_index = @word_list.end; 18 | return bisect2 0, $max_index; 19 | } 20 | 21 | multi sub bisect (Int $num, @list) is export { 22 | sub bisect2 ($low_idx, $high_idx) { 23 | my $mid_idx = (($low_idx + $high_idx) /2).Int; 24 | my $found = @list[$mid_idx]; 25 | return $mid_idx if $num == $found; 26 | return $low_idx if $low_idx >= $high_idx; 27 | if $num < $found { 28 | # search the first half 29 | return bisect2 $low_idx, $mid_idx - 1; 30 | } else { 31 | # search the second half 32 | return bisect2 $mid_idx+1, $high_idx; 33 | } 34 | } 35 | my $max_index = @list.end; 36 | return bisect2 0, $max_index; 37 | } -------------------------------------------------------------------------------- /Supplementary/any_lowercase.pl6: -------------------------------------------------------------------------------- 1 | use v6; 2 | 3 | ### Exercise 7.2 - any_lowervase - only two subroutines are correct ### 4 | 5 | sub is-lower (Str $char) { 6 | return so $char ~~ /^<[a..z]>$/ 7 | } 8 | 9 | sub any_lowercase1(Str $string){ 10 | for $string.split('') -> $char { 11 | next if $char eq ''; 12 | if is-lower $char { 13 | return True; 14 | } else { 15 | return False; 16 | } 17 | } 18 | } 19 | 20 | sub any_lowercase2(Str $string){ 21 | for $string.split('') -> $char { 22 | next if $char eq ''; 23 | if is-lower "char" { 24 | return True; 25 | } else { 26 | return False; 27 | } 28 | } 29 | } 30 | 31 | sub any_lowercase3(Str $string){ 32 | my $flag; 33 | for $string.split('') -> $char { 34 | next if $char eq ''; 35 | $flag = is-lower $char; 36 | } 37 | return $flag; 38 | } 39 | 40 | sub any_lowercase4(Str $string){ 41 | my $flag = False; 42 | for $string.split('') -> $char { 43 | next if $char eq ''; 44 | $flag = $flag || is-lower $char; 45 | } 46 | return $flag; 47 | } 48 | 49 | sub any_lowercase5(Str $string){ 50 | my $flag = False; 51 | for $string.split('') -> $char { 52 | next if $char eq ''; 53 | if is-lower $char { 54 | $flag = True; 55 | } 56 | } 57 | return $flag; 58 | } 59 | 60 | 61 | sub any_lowercase6(Str $string){ 62 | for $string.split('') -> $char { 63 | next if $char eq ''; 64 | if is-lower $char { 65 | return 'true'; 66 | } 67 | } 68 | return 'false'; 69 | } 70 | 71 | sub any_lowercase7(Str $string){ 72 | for $string.split('') -> $char { 73 | next if $char eq ''; 74 | return True if is-lower $char; 75 | } 76 | return False; 77 | } 78 | 79 | sub any_lowercase8(Str $string){ 80 | for $string.split('') -> $char { 81 | next if $char eq ''; 82 | return False unless is-lower $char; 83 | } 84 | return True; 85 | } 86 | 87 | sub any_lowercase9(Str $string){ 88 | for $string.split('') -> $char { 89 | next if $char eq ''; 90 | if not is-lower $char { 91 | return False; 92 | } 93 | return True; 94 | } 95 | } 96 | 97 | 98 | for -> $str { 99 | say "1. $str: ", any_lowercase1 $str; 100 | say "2. $str: ", any_lowercase2 $str; 101 | say "3. $str: ", any_lowercase3 $str; 102 | say "4. $str: ", any_lowercase4 $str; 103 | say "5. $str: ", any_lowercase5 $str; 104 | say "6. $str: ", any_lowercase6 $str; 105 | say "7. $str: ", any_lowercase7 $str; 106 | say "8. $str: ", any_lowercase8 $str; 107 | say "9. $str: ", any_lowercase9 $str; 108 | } -------------------------------------------------------------------------------- /Supplementary/calculator.pl6: -------------------------------------------------------------------------------- 1 | use v6; 2 | 3 | ### Caculator grammar ### 4 | 5 | # use Grammar::Tracer; 6 | my grammar Calculator { 7 | rule TOP { 8 | 9 | } 10 | 11 | rule expr { 12 | + % 13 | } 14 | 15 | token plus-minus-op { 16 | [< + - >] 17 | } 18 | 19 | rule term { 20 | + % 21 | } 22 | 23 | token mult-div-op { 24 | [< * / >] 25 | } 26 | 27 | rule atom { 28 | | { make +$ } 29 | | { make $.made} 30 | } 31 | 32 | rule num { 33 | ? [\d+ | \d+\.\d+ | \.\d+ ] 34 | } 35 | 36 | rule paren-expr { 37 | '(' ')' 38 | } 39 | 40 | token sign { [< + - >] } 41 | } 42 | 43 | class CalcActions { 44 | 45 | method TOP ($/) { 46 | make $.made 47 | } 48 | method expr ($/) { 49 | $.calculate($/, $, $) 50 | } 51 | method term ($/) { 52 | $.calculate($/, $, $) 53 | } 54 | method paren-expr ($/) { 55 | make $.made; 56 | } 57 | 58 | method calculate ($/, $operands, $operators) { 59 | # say "$operands ! $operators"; 60 | my $result = (shift $operands).made; 61 | while my $op = shift $operators { 62 | my $num = (shift $operands).made; 63 | given $op { 64 | when '+' { $result += $num; } 65 | when '-' { $result -= $num; } 66 | when '*' { $result *= $num; } 67 | when '/' { $result /= $num; } 68 | default { die "unknown operator "} 69 | } 70 | } 71 | make $result; 72 | } 73 | } 74 | 75 | 76 | for |< 3*4 5/6 3+5 74-32 5+7/3 5*3*2 (4*5) (3*2)+5 4+3-1/5 4+(3-1)/4 >, 77 | "12 + 6 * 5", " 7 + 12 + 23", " 2 + (10 * 4) ", "3 * (7 + 7)" { 78 | my $result = Calculator.parse($_, :actions(CalcActions)); 79 | printf "%-15s %.3f\n", $/, $result.made if $result; 80 | } 81 | 82 | for "(((2+3)*(5-2))-1)*3", "2 * ((4-1)*((3*7) - (5+2)))" { 83 | my $result = Calculator.parse($_, :actions(CalcActions)); 84 | printf "%-30s %.3f\n", $/, $result.made if $result; 85 | } 86 | -------------------------------------------------------------------------------- /Supplementary/heap2.pl6: -------------------------------------------------------------------------------- 1 | use v6; 2 | 3 | ### Heap implementation ### 4 | 5 | sub build-heap (@array, $index is copy) { 6 | my $index-val = @array[$index]; 7 | while ($index) { 8 | my $parent = Int( ($index - 1) / 2); 9 | my $parent-val = @array[$parent]; 10 | last if $parent-val lt $index-val; 11 | @array[$index] = $parent-val; 12 | $index = $parent; 13 | } 14 | @array[$index] = $index-val; 15 | } 16 | 17 | sub heapify (@array) { 18 | for @array.keys -> $i { 19 | build-heap @array, $i; 20 | # say @array; 21 | } 22 | } 23 | 24 | sub print-heap (@array) { 25 | my $start = 0; 26 | my $end = 0; 27 | my $last = @array.end; 28 | my $step = 1; 29 | loop { 30 | say @array[$start..$end]; 31 | last if $end == $last; 32 | $start += $step; 33 | $step *= 2; 34 | $end += $step; 35 | $end = $last if $end > $last; 36 | } 37 | } 38 | 39 | sub print-heap2 (@array) { 40 | my $step = 0; 41 | for @array.keys -> $current { 42 | my $left_child = @array[2 * $current + 1]; 43 | say "$current\tNode = @array[$current];\tNo child" and next unless defined $left_child; 44 | my $right_child = @array[2 * $current + 2] // "' '"; 45 | 46 | say "$current\tNode = @array[$current];\tChildren: $left_child and $right_child"; 47 | $step++; 48 | } 49 | 50 | } 51 | 52 | my @input = ; # ; 53 | heapify @input; 54 | say @input; 55 | print-heap @input; 56 | print-heap2 @input; 57 | 58 | -------------------------------------------------------------------------------- /Supplementary/json_grammar.pl6: -------------------------------------------------------------------------------- 1 | 2 | 3 | grammar JSON-Grammar { 4 | token TOP { \s* [ | ] \s* } 5 | rule object { '{' \s* '}' \s* } 6 | rule pairlist { * % \, } 7 | rule pair { ':' } 8 | rule array { '[' ']'} 9 | rule valueList { * % \, } 10 | token string { \" ( <[ \w \s \- ' ]>+ ) \" } 11 | token number { 12 | [\+|\-]? 13 | [ \d+ [ \. \d+ ]? ] | [ \. \d+ ] 14 | [ <[eE]> [\+|\-]? \d+ ]? 15 | } 16 | token value { | | | 17 | | true | false | null 18 | } 19 | } 20 | 21 | my $JSON-string = q/{ 22 | "firstName": "John", 23 | "lastName": "Smith", 24 | "isAlive": true, 25 | "age": 25, 26 | "address": { 27 | "streetAddress": "21 2nd Street", 28 | "city": "New York", 29 | "state": "NY", 30 | "postalCode": "10021-3100" 31 | }, 32 | "phoneNumbers": [ 33 | { 34 | "type": "home", 35 | "number": "212 555-1234" 36 | }, 37 | { 38 | "type": "office", 39 | "number": "646 555-4567" 40 | }, 41 | { 42 | "type": "mobile", 43 | "number": "123 456-7890" 44 | } 45 | ], 46 | "children": [], 47 | "spouse": null, 48 | "Bank-account": { 49 | "credit": 2342.25 50 | } 51 | }/; 52 | 53 | class JSON-actions { 54 | method TOP($/) { 55 | make $/.values.[0].made; 56 | }; 57 | method object($/) { 58 | make $.made.hash.item; 59 | } 60 | method pairlist($/) { 61 | make $».made.flat; 62 | } 63 | method pair($/) { 64 | # say ~$/; 65 | make $.made => $.made; 66 | } 67 | method array($/) { 68 | make $.made.item; 69 | } 70 | method valueList($/) { 71 | make [$.map(*.made)]; 72 | } 73 | method string($/) { make ~$0 } 74 | method number($/) { make +$/.Str; } 75 | method value($/) { 76 | given ~$/ { 77 | when "true" {make Bool::True;} 78 | when "false" {make Bool::False;} 79 | when "null" {make Any;} 80 | default { make $.made;} 81 | } 82 | } 83 | } 84 | 85 | my $j-actions = JSON-actions.new(); 86 | my $match = JSON-Grammar.parse($JSON-string, :actions($j-actions)); 87 | say $match.made; 88 | # say $match.made if $match; 89 | #my $hash = $match.made.hash; 90 | #say $hash; 91 | #say $hash.keys; 92 | #say $hash; 93 | say "Keys are: \n", $match.made.keys; 94 | say "\nSome values:"; 95 | say $match.made{$_} for ; 96 | say $match.made
; 97 | say "\nPhone numbers:"; 98 | say $match.made[$_] for 0..$match.made.end; 99 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /Supplementary/pixel.pl6: -------------------------------------------------------------------------------- 1 | use v6; 2 | 3 | ### Class Pixel subclassing class Point2D ### 4 | 5 | class Point2D { 6 | has Numeric $.abscissa; 7 | has Numeric $.ordinate; 8 | 9 | method coordinates { # accessor to both x and y 10 | return (self.abscissa, self.ordinate) 11 | } 12 | 13 | method distanceToCenter { 14 | (self.abscissa ** 2 + self.ordinate ** 2) ** 0.5 15 | } 16 | method polarCoordinates { 17 | my $radius = self.distanceToCenter; 18 | my $theta = atan2 self.ordinate, self.abscissa; # (azimut) 19 | return $radius, $theta; 20 | } 21 | } 22 | 23 | class Pixel is Point2D { 24 | has %.color is rw; 25 | 26 | multi method change_color(%hue) { 27 | self.color = %hue 28 | } 29 | multi method change_color(Int $red, Int $green, Int $blue) { 30 | # signature using positional parameters 31 | self.color = (red => $red, green => $green, blue => $blue) 32 | } 33 | } 34 | 35 | my $pix = Pixel.new( 36 | :abscissa(3.3), 37 | :ordinate(4.2), 38 | color => {red => 34, green => 233, blue => 145}, 39 | ); 40 | 41 | say "The original pixel has the following colors: ", $pix.color; 42 | 43 | $pix.change_color({:red(195), :green(110), :blue(70),}); 44 | say "The modified pixelhas the following colors: ", $pix.color; 45 | printf "New pixel caracteristics: \n\tAbscissa: %.2f\n\tOrdinate: %.2f\n\tColors: R: %d, G: %d, B: %d\n", 46 | $pix.abscissa, $pix.ordinate, $pix.color, $pix.color{"green"}, $pix.color{"blue"}; 47 | 48 | $pix.change_color(90, 180, 30); # positional args 49 | say "New colors: 50 | \tR: {$pix.color}, V: {$pix.color}, B: {$pix.color} "; 51 | -------------------------------------------------------------------------------- /book/Makefile: -------------------------------------------------------------------------------- 1 | ### Input and output files/dir 2 | FILENAME = thinkperl6 3 | OUTPUT_NAME = thinkperl6 4 | PDF_OUTPUT = pdflatex 5 | DIR_NAME = tmpDir 6 | 7 | 8 | ### Compilation flags for pdflatex, xelatex, etc. 9 | PDFLATEX_FLAGS = -halt-on-error\ 10 | -interaction=batchmode\ 11 | -output-format pdf\ 12 | -output-directory tmpDir\ 13 | -jobname=$(OUTPUT_NAME) 14 | XELATEX_FLAGS = -halt-on-error\ 15 | -interaction=batchmode\ 16 | -output-directory tmpDir\ 17 | -jobname=$(OUTPUT_NAME) 18 | 19 | TEXINPUTS = .:$(DIR_NAME)/ 20 | TEXMFOUTPUT = $(DIR_NAME) 21 | 22 | ### Choose TeX engine 23 | FLAGS = $(PDFLATEX_FLAGS) 24 | 25 | ### Compile tex into pdf 26 | all: $(DIR_NAME)/$(FILENAME).pdf 27 | 28 | $(DIR_NAME)/: 29 | mkdir -p $(DIR_NAME) 30 | 31 | $(DIR_NAME)/$(FILENAME).aux: $(DIR_NAME)/ 32 | $(PDF_OUTPUT) $(FLAGS) $(FILENAME) 33 | 34 | $(DIR_NAME)/$(FILENAME).pdf: $(DIR_NAME)/$(FILENAME).aux 35 | $(PDF_OUTPUT) $(FLAGS) $(FILENAME) 36 | makeindex $(DIR_NAME)/$(OUTPUT_NAME).idx 37 | $(PDF_OUTPUT) $(FLAGS) $(FILENAME) 38 | 39 | ### Clean 40 | # Clean temporary files (including created PDF file) by removing 41 | # the directory tmpDir/ created during the compilation process. 42 | 43 | pdf: 44 | mv ./$(DIR_NAME)/$(FILENAME).pdf ../PDF/ 45 | 46 | clean: 47 | rm -rfv $(DIR_NAME) 48 | -------------------------------------------------------------------------------- /book/chapt1.tex: -------------------------------------------------------------------------------- 1 | \chapter{The Way of the Program} 2 | 3 | The goal of this book is to teach you to think like a computer 4 | scientist. This way of thinking combines some of the best features of 5 | mathematics, engineering, and natural science. Like mathematicians, 6 | computer scientists use formal languages to denote ideas (specifically 7 | computations). Like engineers, they design things, assembling 8 | components into systems and evaluating tradeoffs among alternatives. 9 | Like scientists, they observe the behavior of complex systems, form 10 | hypotheses, and test predictions. 11 | \index{problem solving} 12 | \index{formal language} 13 | 14 | The single most important skill for a computer scientist is {\bf 15 | problem solving}. Problem solving means the ability to formulate 16 | problems, think creatively about solutions, and express a solution 17 | clearly and accurately. As it turns out, the process of learning to 18 | program is an excellent opportunity to practice problem-solving 19 | skills. That's why this chapter is called, ``The Way of the 20 | Program.'' 21 | 22 | On one level, you will be learning to program, a useful skill by 23 | itself. On another level, you will use programming as a means to an 24 | end. As we go along, that end will become clearer. 25 | \index{programming} 26 | 27 | 28 | \section{What is a Program?} 29 | 30 | A {\bf program} is a sequence of instructions that specifies how to 31 | perform a computation. The computation might be something 32 | mathematical, such as solving a system of equations or finding the 33 | roots of a polynomial, but it can also be a symbolic computation, such 34 | as searching and replacing text in a document, or something 35 | graphical, like processing an image or playing a video. 36 | \index{program} 37 | 38 | The details look different in different languages, but a few basic 39 | instructions appear in just about every language: 40 | 41 | \begin{description} 42 | 43 | \item[Input] Get data from the keyboard, a file, the network, 44 | a sensor, a GPS chip or some other device. 45 | \index{input} 46 | 47 | \item[Output] Display data on the screen, save it in a 48 | file, send it over the network, act on a mechanical device, etc. 49 | \index{output} 50 | 51 | \item[Math] Perform basic mathematical operations like addition and 52 | multiplication. 53 | 54 | \item[Conditional execution] Check for certain conditions and 55 | run the appropriate code. 56 | \index{conditional!execution} 57 | 58 | \item[Repetition] Perform some action repeatedly, usually with 59 | some variation. 60 | \index{repetition} 61 | 62 | \end{description} 63 | 64 | Believe it or not, that's pretty much all there is to it. Every 65 | program you've ever used, no matter how complicated, is made up of 66 | instructions that look pretty much like these. So you can think of 67 | programming as the process of breaking a large, complex task 68 | into smaller and smaller subtasks until the subtasks are 69 | simple enough to be performed with one of these basic instructions. 70 | \index{instruction} 71 | 72 | \index{abstraction} 73 | \index{subtask} 74 | Using or calling these subtasks makes it possible to create 75 | various levels of \emph{abstraction}. You have probably 76 | been told that computers only use 0's and 1's at the 77 | lowest level; but we usually don't have to worry about that. 78 | When we use a word processor to write a letter or a report, 79 | we are interested in files containing text and some 80 | formatting instructions, and with commands to change the 81 | file or to print it; fortunately, we don't have to care 82 | about the underlying 0's and 1's; the word-processing 83 | program offers us a much higher view (files, 84 | commands, etc.) that hides the gory underlying details. 85 | 86 | Similarly, when we write a program, 87 | we usually use and/or create several layers of abstraction, 88 | so that, for example, once we have created a subtask that 89 | queries a database and stores the relevant data in 90 | memory, we no longer have to worry about the technical 91 | details of the subtask. We can use it as a sort of black 92 | box that will perform the desired operation for us. 93 | The essence of programming is to a very large extent this 94 | art of creating these successive layers of abstraction 95 | so that performing the higher level tasks becomes 96 | relatively easy. 97 | \index{subtask} 98 | \index{black box} 99 | 100 | 101 | \section{Running Perl~6} 102 | \label{running_perl_6} 103 | 104 | One of the challenges of getting started with Perl~6 is that you 105 | might have to install Perl~6 and related software on your computer. 106 | If you are familiar with your operating system, and especially 107 | if you are comfortable with the shell or command-line interface, 108 | you will have no trouble installing Perl~6. But for beginners, 109 | it can be painful to learn about system administration and 110 | programming at the same time. 111 | 112 | To avoid that problem, you can start out running Perl~6 113 | in a web browser. You might want to use a search engine 114 | to find such a site. Currently, the easiest is probably 115 | to connect to the \url{https://glot.io/new/perl6} site, 116 | where you can type some Perl~6 code in the main window, run 117 | it, and see the result in the output window below. 118 | \index{Perl~6 in a browser} 119 | 120 | Sooner or later, however, you will really need to install 121 | Perl~6 on your computer. 122 | 123 | The easiest way to install Perl~6 on your system is to 124 | download Rakudo Star (a distribution of Perl~6 that contains 125 | the Rakudo Perl~6 {\bf compiler}, documentation and useful modules): 126 | follow the instructions for your operating system at 127 | \url{http://rakudo.org/how-to-get-rakudo/} and at 128 | \url{https://perl6.org/downloads/}. 129 | 130 | \index{Perl 6 version} 131 | As of this writing, the most recent specification of 132 | the language is Perl~6 version 6c (v6.c), and the most 133 | recent release available for download is Rakudo Star 2016.07; 134 | the examples in this book should 135 | all run with this version. You can find out the installed 136 | version by issuing the following command at the operating 137 | system prompt: 138 | \begin{verbatim} 139 | $ perl6 -v 140 | This is Rakudo version 2016.07.1 built on MoarVM version 2016.07 141 | implementing Perl 6.c. 142 | \end{verbatim} 143 | 144 | However, you should probably download and install the most recent 145 | version you can find. The output (warnings, error messages, 146 | etc.) you'll get from your version of Perl might in some 147 | cases slightly differ from what is printed in this book, 148 | but these possible differences should essentially be 149 | only cosmetic. 150 | 151 | Compared to Perl~5, Perl~6 is not just a new version of Perl. 152 | It is more like the new little sister of Perl~5. It does not 153 | aim at replacing Perl~5. Perl~6 is really a new programming language, 154 | with a syntax that is similar to earlier versions of 155 | Perl (such as Perl~5), but still markedly different. Unless 156 | stated otherwise, this book is about Perl~6 only, not about Perl~5 157 | and preceding versions of the Perl programming language. From now on, 158 | whenever we speak about \emph{Perl} with no further qualification, 159 | we mean Perl~6. 160 | 161 | The Perl~6 {\bf interpreter} is a program that reads and 162 | executes Perl~6 code. It is sometimes called REPL (for ``read, 163 | evaluate, print, loop''). Depending on your environment, you 164 | might start the interpreter by clicking on an icon, or by 165 | typing {\tt perl6} on a command line. 166 | 167 | When it starts, you should see output like this: 168 | \index{interpreter} 169 | \index{REPL} 170 | 171 | \begin{verbatim} 172 | To exit type 'exit' or '^D' 173 | (Possibly some information about Perl and related software) 174 | > 175 | \end{verbatim} 176 | % 177 | 178 | The last line with {\tt >} is a {\bf prompt} that indicates 179 | that the REPL is ready for you to enter code. If you type a 180 | line of code and hit Enter, the interpreter displays the 181 | result: 182 | \index{prompt} 183 | 184 | \begin{verbatim} 185 | > 1 + 1 186 | 2 187 | > 188 | \end{verbatim} 189 | % 190 | You can type exit at the REPL prompt to exit the REPL. 191 | 192 | Now you're ready to get started. 193 | From here on, we assume that you know how to start the Perl~6 194 | REPL and run code. 195 | 196 | 197 | \section{The First Program} 198 | \label{hello} 199 | \index{Hello, World} 200 | 201 | Traditionally, the first program you write in a new language 202 | is called ``Hello, World'' because all it does is display the 203 | words ``Hello, World.'' In Perl~6, it looks like this: 204 | 205 | \begin{verbatim} 206 | > say "Hello, World"; 207 | Hello, World 208 | > 209 | \end{verbatim} 210 | % 211 | \index{say function or method} 212 | \index{function!say} 213 | This is an example of what is usually called a {\bf print statement}, although it 214 | doesn't actually print anything on paper and doesn't even 215 | use the {\tt print} keyword \footnote{Perl also has a {\tt print} 216 | function, but the {\tt say} built-in function is used here 217 | because it adds a new line character to the output.} (keywords are 218 | words which have a special meaning to the language and are 219 | used by the interpreter to recognize the structure of the program). 220 | The print statement displays a result on the screen. In this case, 221 | the result is the words {\tt Hello, World}. 222 | % 223 | The quotation marks in the program indicate the beginning and end 224 | of the text to be displayed; they don't appear in the result. 225 | \index{quotation mark} 226 | \index{print statement} 227 | \index{statement!print} 228 | 229 | The semi-colon ``{\tt ;}'' at the end of the line indicates 230 | that this is the end of the current statement. Although a 231 | semi-colon is technically not needed when running 232 | simple code directly under the REPL, it is usually 233 | necessary when writing a program with several lines of code, 234 | so you might as well just get into the habit of ending code 235 | instructions with a semi-colon. 236 | \index{semi-colon} 237 | 238 | Many other programming languages would require parentheses 239 | around the sentence to be displayed, but this is usually 240 | not necessary in Perl~6. 241 | 242 | \section{Arithmetic Operators} 243 | \index{operator!arithmetic} 244 | \index{arithmetic operator} 245 | 246 | After ``Hello, World,'' the next step is arithmetic. Perl~6 provides 247 | {\bf operators}, which are special symbols that represent computations 248 | like addition and multiplication. 249 | 250 | The operators {\tt +}, {\tt -}, {\tt *}, and {\tt /} perform addition, 251 | subtraction, multiplication and division, as in the following examples 252 | under the REPL: 253 | 254 | \begin{verbatim} 255 | > 40 + 2 256 | 42 257 | > 43 - 1 258 | 42 259 | > 6 * 7 260 | 42 261 | > 84 / 2 262 | 42 263 | \end{verbatim} 264 | % 265 | 266 | Since we use the REPL, we don't need an explicit print 267 | statement in these examples, as the REPL automatically 268 | prints out the result of the statements for us. In a real 269 | program, you would need a print statement to display 270 | the result, as we'll see later. Similarly, if you run 271 | Perl statements in the web browser mentioned in 272 | Section~\ref{running_perl_6}, you will need a 273 | print statement to display the result of these operations. 274 | For example: 275 | 276 | \begin{verbatim} 277 | say 40 + 2; # -> 42 278 | \end{verbatim} 279 | 280 | 281 | Finally, the operator {\tt **} performs exponentiation; that is, 282 | it raises a number to a power: 283 | 284 | \begin{verbatim} 285 | > 6**2 + 6 286 | 42 287 | \end{verbatim} 288 | % 289 | In some other languages, the caret (``\verb"^"'') or 290 | circumflex accent is used for exponentiation, but in 291 | Perl~6 it is used for some other purposes. 292 | % 293 | \index{set} 294 | \index{set!operator} 295 | \index{operator!set} 296 | 297 | 298 | \section{Values and Types} 299 | \label{values_and_types} 300 | \index{value} 301 | \index{type} 302 | \index{string} 303 | 304 | A {\bf value} is one of the basic things a program works with, like a 305 | letter or a number. Some values we have seen so far are {\tt 2}, 306 | {\tt 42}, and \verb'"Hello, World"'. 307 | 308 | These values belong to different {\bf types}: 309 | {\tt 2} is an {\bf integer}, {\tt 40 + 2} is also an integer, 310 | {\tt 84/2} is a {\bf rational number}, 311 | and \verb"'Hello, World'" is a {\bf string}, so called 312 | because the characters it contains are strung together. 313 | \index{integer} 314 | \index{floating-point} 315 | 316 | If you are not sure what type a value has, Perl can 317 | tell you: 318 | 319 | \begin{verbatim} 320 | > say 42.WHAT; 321 | (Int) 322 | > say (40 + 2).WHAT; 323 | (Int) 324 | > say (84 / 2).WHAT; 325 | (Rat) 326 | > say (42.0).WHAT 327 | (Rat) 328 | > say ("Hello, World").WHAT; 329 | (Str) 330 | > 331 | \end{verbatim} 332 | % 333 | In these instructions, {\tt .WHAT} is known as an 334 | introspection method, that is a kind of method which 335 | will tell you \emph{what} (of which type) the preceding 336 | expression is. {\tt 42.WHAT} is an example of the dot 337 | syntax used for method invocation: it calls the {\tt .WHAT} 338 | built-in on the ``42'' expression (the invocant) and provides 339 | to the {\tt say} function the result of this invocation, 340 | which in this case is the type of the expression. 341 | \index{WHAT} 342 | \index{introspection} 343 | \index{string!type} 344 | \index{type!Str} 345 | \index{Int type} 346 | \index{type!Int} 347 | \index{rational!type} 348 | \index{type!Rat} 349 | \index{invocant} 350 | \index{invocation} 351 | 352 | Not surprisingly, integers belong to the type {\tt Int}, 353 | strings belong to {\tt Str} and rational 354 | numbers belong to {\tt Rat}. 355 | 356 | Although {\tt 40 + 2} and {\tt 84 / 2} seem to yield the 357 | same result (42), the first expression returns an integer 358 | ({\tt Int}) and the second a rational number ({\tt Rat}). 359 | The number 42.0 is also a rational. 360 | 361 | The rational type is somewhat uncommon in most programming 362 | languages. Internally, these numbers are stored as two 363 | integers representing the numerator and the denominator 364 | (in their simplest terms). For example, the number 17.3 365 | might be stored as two integers, 173 and 10, meaning that 366 | Perl is really storing something meaning the $\frac{173}{10}$ 367 | fraction. Although this is usually not needed (except 368 | for introspection or debugging), you might access these 369 | two integers with the following methods: 370 | 371 | \begin{verbatim} 372 | > my $num = 17.3; 373 | 17.3 374 | > say $num.WHAT; 375 | (Rat) 376 | > say $num.numerator, " ", $num.denominator; # say can print a list 377 | 173 10 378 | > say $num.nude; # "nude" stands for numerator-denominator 379 | (173 10) 380 | \end{verbatim} 381 | \index{numerator method} 382 | \index{method!numerator} 383 | \index{denominator method} 384 | \index{method!denominator} 385 | \index{nude method} 386 | \index{method!nude} 387 | % 388 | This may seem anecdotal, but, for reasons which are 389 | beyond the scope of this book, this makes it possible for Perl~6 390 | to perform arithmetical operations on rational numbers with 391 | a much higher accuracy than most common programming languages. 392 | For example, if you try to perform the arithmetical operation 393 | \verb'0.3 - 0.2 - 0.1', with most general purpose programming languages 394 | (and depending on your machine architecture), you 395 | might obtain a result such as -2.77555756156289e-17 (in Perl~5), 396 | -2.775558e-17 (in C under gcc), or -2.7755575615628914e-17 397 | (Java, Python~3, Ruby, TCL). Don't worry about these values if you 398 | don't understand them, let us just say that they are 399 | extremely small, but they are not 0, whereas, 400 | obviously, the result should really be zero. In Perl~6, 401 | the result is 0 (even to the fiftieth decimal digit): 402 | \begin{verbatim} 403 | > my $result-should-be-zero = 0.3 - 0.2 - 0.1; 404 | 0 405 | > printf "%.50f", $result-should-be-zero; # prints 50 decimal digits 406 | 0.00000000000000000000000000000000000000000000000000 407 | \end{verbatim} 408 | % 409 | In Perl~6, you might even compare the result of the operation with 0: 410 | \begin{verbatim} 411 | > say $result-should-be-zero == 0; 412 | True 413 | \end{verbatim} 414 | % 415 | Don't do such a comparison with most common programming 416 | languages; you're very likely to get a wrong result. 417 | 418 | What about values like \verb'"2"' and \verb'"42.0"'? 419 | They look like numbers, but they are in quotation marks like 420 | strings. 421 | \index{quotation mark} 422 | 423 | \begin{verbatim} 424 | > say '2'.perl; # perl returns a Perlish representation of the invocant 425 | "2" 426 | > say "2".WHAT; 427 | (Str) 428 | > say '42'.WHAT; 429 | (Str) 430 | \end{verbatim} 431 | % 432 | \index{invocant} 433 | 434 | They're strings because they are defined within quotes. Although 435 | Perl will often perform the necessary conversions for you, it 436 | is generally a good practice not to use quotation marks if your value 437 | is intended to be a number. 438 | 439 | When you type a large integer, you might be tempted to use commas 440 | between groups of digits, as in {\tt 1,234,567}. This is not a 441 | legal {\em integer} in Perl~6, but it is a legal expression: 442 | 443 | \begin{verbatim} 444 | > 1,234,567 445 | (1 234 567) 446 | > 447 | \end{verbatim} 448 | % 449 | That's actually a list of three different integer numbers, and 450 | not what we expected at all! 451 | 452 | \begin{verbatim} 453 | > say (1,234,567).WHAT 454 | (List) 455 | \end{verbatim} 456 | 457 | Perl~6 interprets {\tt 1,234,567} as a comma-separated 458 | sequence of three integers. As we will see later, 459 | the comma is a separator used for constructing lists. 460 | \index{comma} 461 | 462 | You can, however, separate groups of digits with the underscore character ``\verb"_"'' for better legibility and obtain a 463 | proper integer: 464 | \index{underscore character} 465 | 466 | \begin{verbatim} 467 | > 1_234_567 468 | 1234567 469 | > say 1_234_567.WHAT 470 | (Int) 471 | > 472 | \end{verbatim} 473 | % 474 | 475 | \index{sequence} 476 | 477 | 478 | 479 | \section{Formal and Natural Languages} 480 | \index{formal language} 481 | \index{natural language} 482 | \index{language!formal} 483 | \index{language!natural} 484 | 485 | {\bf Natural languages} are the languages people speak, 486 | such as English, Spanish, and French. They were not designed 487 | by people (although people try to impose some order on them); 488 | they evolved naturally. 489 | 490 | {\bf Formal languages} are languages that are designed by people for 491 | specific applications. For example, the notation that mathematicians 492 | use is a formal language that is particularly good at denoting 493 | relationships among numbers and symbols. Chemists use a formal 494 | language to represent the chemical structure of molecules. And 495 | most importantly: 496 | 497 | \begin{quote} 498 | {\bf Programming languages are formal languages that have been 499 | designed to express computations.} 500 | \end{quote} 501 | 502 | Formal languages tend to have strict {\bf syntax} rules that 503 | govern the structure of statements. 504 | For example, in mathematics the statement 505 | $3 + 3 = 6$ has correct syntax, but 506 | not $3 + = 3 \$ 6$. In chemistry 507 | $H_2O$ is a syntactically correct formula, but $_2Zz$ is not. 508 | \index{syntax} 509 | 510 | Syntax rules come in two flavors, pertaining to {\bf tokens} and 511 | {\bf structure}. Tokens are the basic elements of the language, such as 512 | words, numbers, and chemical elements. One of the problems with 513 | $3 += 3 \$ 6$ is that \( \$ \) is not a legal token in mathematics 514 | (at least as far as I know). Similarly, $_2Zz$ is not legal because 515 | there is no chemical element with the abbreviation $Zz$. 516 | \index{token} 517 | \index{structure} 518 | 519 | The second type of syntax rule, structure, pertains to the way tokens are 520 | combined. The equation $3 += 3$ is illegal in mathematics 521 | because even though $+$ and $=$ are legal tokens, you can't 522 | have one right after the other. Similarly, in a chemical formula, 523 | the subscript representing the number of atoms in a 524 | chemical compound comes after the element name, not before. 525 | 526 | This is @ well-structured Engli\$h 527 | sentence with invalid t*kens in it. This sentence all valid 528 | tokens has, but invalid structure with. 529 | 530 | When you read a sentence in English or a statement in a formal 531 | language, you have to figure out the structure 532 | (although in a natural language you do this subconsciously). This 533 | process is called {\bf parsing}. 534 | \index{parse} 535 | 536 | Although formal and natural languages have many features in 537 | common---tokens, structure, and syntax---there are some 538 | differences: 539 | \index{ambiguity} 540 | \index{redundancy} 541 | \index{literalness} 542 | 543 | \begin{description} 544 | 545 | \item[Ambiguity] Natural languages are full of ambiguity, which 546 | people deal with by using contextual clues and other information. 547 | Formal languages are designed to be nearly or completely unambiguous, 548 | which means that any statement has exactly one meaning. 549 | 550 | \item[Redundancy] In order to make up for ambiguity and reduce 551 | misunderstandings, natural languages employ lots of 552 | redundancy. As a result, they are often verbose. Formal languages 553 | are less redundant and more concise. 554 | 555 | \item[Literalness] Natural languages are full of idiom and metaphor. 556 | If we say, ``The penny dropped,'' there is probably no penny and 557 | nothing dropping (this idiom means that someone understood something 558 | after a period of confusion). Formal languages 559 | mean exactly what they say. 560 | 561 | \end{description} 562 | 563 | Because we all grow up speaking natural languages, it is sometimes 564 | hard to adjust to formal languages. The difference between formal and 565 | natural language is like the difference between poetry and prose, but 566 | more so: \index{poetry} \index{prose} 567 | 568 | \begin{description} 569 | 570 | \item[Poetry] Words are used for their sounds as well as for 571 | their meaning, and the whole poem together creates an effect or 572 | emotional response. Ambiguity is not only common but often 573 | deliberate. 574 | 575 | \item[Prose] The literal meaning of words is more important, 576 | and the structure contributes more meaning. Prose is more amenable to 577 | analysis than poetry but still often ambiguous. 578 | 579 | \item[Programs] The meaning of a computer program is unambiguous 580 | and literal, and can be understood entirely by analysis of the 581 | tokens and structure. 582 | 583 | \end{description} 584 | 585 | Formal languages are more dense 586 | than natural languages, so it takes longer to read them. Also, the 587 | structure is important, so it is not always best to read 588 | from top to bottom, left to right. Instead, learn to parse the 589 | program in your head, identifying the tokens and interpreting the 590 | structure. Finally, the details matter. Small errors in 591 | spelling and punctuation, which you can get away 592 | with in natural languages, can make a big difference in a formal 593 | language. 594 | 595 | 596 | \section{Debugging} 597 | \index{debugging} 598 | 599 | Programmers make mistakes. Programming errors are usually 600 | called {\bf bugs} and the process of tracking them down is called 601 | {\bf debugging}. 602 | \index{debugging} 603 | \index{bug} 604 | 605 | Programming, and especially debugging, sometimes brings out strong 606 | emotions. If you are struggling with a difficult bug, you might 607 | feel angry, despondent, or embarrassed. 608 | 609 | There is evidence that people naturally respond to computers as if 610 | they were people. When they work well, we think 611 | of them as teammates, and when they are obstinate or rude, we 612 | respond to them the same way we respond to rude, 613 | obstinate people\footnote{Reeves and Nass, {\it The Media 614 | Equation: How People Treat Computers, Television, and New Media 615 | Like Real People and Places}, (Center for the Study of Language and Information, 2003).)}. 616 | \index{debugging!emotional response} 617 | \index{emotional debugging} 618 | 619 | Preparing for these reactions might help you deal with them. 620 | One approach is to think of the computer as an employee with 621 | certain strengths, like speed and precision, and 622 | particular weaknesses, like lack of empathy and inability 623 | to grasp the big picture. 624 | 625 | Your job is to be a good manager: find ways to take advantage 626 | of the strengths and mitigate the weaknesses. And find ways 627 | to use your emotions to engage with the problem, 628 | without letting your reactions interfere with your ability 629 | to work effectively. 630 | 631 | Learning to debug can be frustrating, but it is a valuable skill 632 | that is useful for many activities beyond programming. At the 633 | end of each chapter there is a section, like this one, 634 | with our suggestions for debugging. I hope they help! 635 | 636 | 637 | \section{Glossary} 638 | 639 | \begin{description} 640 | 641 | \item[Problem solving] The process of formulating a problem, finding 642 | a solution, and expressing it. 643 | \index{problem solving} 644 | 645 | \item[Abstraction] A way of providing a high-level view 646 | of a task and hiding the underlying technical details so 647 | that this task becomes easy. 648 | 649 | \item[Interpreter] A program that reads another program and executes it 650 | \index{interpret} 651 | 652 | \item[Compiler] A program that reads another program and 653 | transforms it into executable computer code; there used to be 654 | a strong difference between interpreted and compiled languages, 655 | but this distinction has become blurred over the last 656 | two decades or so. 657 | \index{compiler} 658 | 659 | \item[Prompt] Characters displayed by the interpreter to indicate 660 | that it is ready to take input from the user. 661 | \index{prompt} 662 | 663 | \item[Program] A set of instructions that specifies a computation. 664 | \index{program} 665 | 666 | \item[Print statement] An instruction that causes the Perl~6 667 | interpreter to display a value on the screen. 668 | \index{print statement} 669 | \index{statement!print} 670 | 671 | \item[Operator] A special symbol that represents a simple computation like 672 | addition, multiplication, or string concatenation. 673 | \index{operator} 674 | 675 | \item[Value] One of the basic units of data, like a number or string, 676 | that a program manipulates. 677 | \index{value} 678 | 679 | \item[Type] A category of values. The types we have seen so far 680 | are integers (type {\tt Int}), rational numbers (type {\tt 681 | Rat}), and strings (type {\tt Str}). 682 | \index{type} 683 | 684 | \item[Integer] A type that represents whole numbers. 685 | \index{integer} 686 | 687 | \item[Rational] A type that represents numbers with fractional 688 | parts. Internally, Perl stores a rational as two integers 689 | representing respectively the numerator and the denominator 690 | of the fractional number. 691 | \index{rational} 692 | 693 | \item[String] A type that represents sequences of characters. 694 | \index{string} 695 | 696 | \item[Natural language] Any one of the languages that people speak that 697 | evolved naturally. 698 | \index{natural language} 699 | 700 | \item[Formal language] Any one of the languages that people have designed 701 | for specific purposes, such as representing mathematical ideas or 702 | computer programs; all programming languages are formal languages. 703 | \index{formal language} 704 | 705 | \item[Token] One of the basic elements of the syntactic structure of 706 | a program, analogous to a word in a natural language. 707 | \index{token} 708 | 709 | \item[Syntax] The rules that govern the structure of a program. 710 | \index{syntax} 711 | 712 | \item[Parse] To examine a program and analyze the syntactic structure. 713 | \index{parse} 714 | 715 | \item[Bug] An error in a program. 716 | \index{bug} 717 | 718 | \item[Debugging] The process of finding and correcting bugs. 719 | \index{debugging} 720 | 721 | \end{description} 722 | 723 | 724 | \section{Exercises} 725 | 726 | \begin{exercise} 727 | 728 | It is a good idea to read this book in front of a computer so you 729 | can try out the examples as you go. 730 | 731 | Whenever you are experimenting with a new feature, you should try 732 | to make mistakes. For example, in the ``Hello, world!'' program, 733 | what happens if you leave out one of the quotation marks? What 734 | if you leave out both? What if you spell {\tt say} wrong? 735 | \index{error message} 736 | 737 | This kind of experiment helps you remember what you read; it also 738 | helps when you are programming, because you get to know what the error 739 | messages mean. It is better to make mistakes now and on purpose than 740 | later and accidentally. 741 | 742 | Please note that most exercises in this book are provided with 743 | a solution in the appendix. However, the exercises in this chapter 744 | and in the next chapter are not intended to let you solve an 745 | actual problem but are designed to simply let you experiment 746 | with the Perl interpreter; there is no good solution, just try 747 | out what is proposed to get a feeling on how it works. 748 | 749 | \begin{enumerate} 750 | 751 | \item If you are trying to print a string, what happens if you 752 | leave out one of the quotation marks, or both? 753 | 754 | \item You can use a minus sign to make a negative number like 755 | {\tt -2}. What happens if you put a plus sign before a number? 756 | What about {\tt 2++2}? 757 | 758 | \item In math notation, leading zeros are OK, as in {\tt 02}. 759 | What happens if you try this in Perl? 760 | 761 | \item What happens if you have two values with no operator 762 | between them, such as {\tt say 2 2;}? 763 | 764 | \end{enumerate} 765 | 766 | \end{exercise} 767 | 768 | 769 | 770 | \begin{exercise} 771 | 772 | Start the Perl~6 REPL interpreter and use it as a calculator. 773 | 774 | \begin{enumerate} 775 | 776 | \item How many seconds are there in 42 minutes, 42 seconds? 777 | 778 | \item How many miles are there in 10 kilometers? Hint: there are 1.61 779 | kilometers in a mile. 780 | 781 | \item If you run a 10 kilometer race in 42 minutes, 42 seconds, what is 782 | your average pace (time per mile in minutes and seconds)? What is 783 | your average speed in miles per hour? 784 | 785 | \index{calculator} 786 | \index{running pace} 787 | 788 | \end{enumerate} 789 | 790 | \end{exercise} 791 | 792 | 793 | -------------------------------------------------------------------------------- /book/conclusion.tex: -------------------------------------------------------------------------------- 1 | \chapter{Some Final Advice} 2 | 3 | \begin{quote} 4 | \raggedleft 5 | \emph{Everyone knows that debugging is twice as hard as writing \\ 6 | a program in the first place. So if you're as clever as you \\ 7 | can be when you write it, how will you ever debug it? }\\ 8 | --- Brian Kernighan, "The Elements of Programming Style". 9 | \end{quote} 10 | \index{Kernighan, Brian} 11 | 12 | \section{Make it Clear, Keep it Simple} 13 | 14 | Writing a real-life program is not the same thing as learning 15 | the art of programming or learning a new language. 16 | 17 | Because the goal of this book is to lead you to learn 18 | more advanced concepts or new syntax, I have often been 19 | pushing new ways of doing things. But this does not mean that 20 | you should try to pack your most advanced knowledge into 21 | each of your programs. Quite the contrary. 22 | 23 | The rule of thumb is ``KISS'': keep it simple, stupid. The 24 | KISS engineering principle (originated in the US Navy 25 | around 1960) states that most systems work best if they 26 | are kept simple rather than made complicated; therefore 27 | simplicity should be a key goal in design and unnecessary 28 | complexity should be avoided. This does not mean, however, 29 | that you should write simplistic code. 30 | \index{KISS: keep it simple, stupid} 31 | 32 | As an example, if you're looking for a literal substring 33 | within a string, use the simple {\tt index} built-in function, 34 | rather than firing the regex engine for that. Similarly, 35 | if you know the position and length of the substring, then 36 | use the {\tt substr} function. But if you need a more ``fuzzy'' 37 | match with perhaps some alternatives or a character class, then 38 | a regex is very likely the right tool. 39 | \index{index} 40 | \index{substr} 41 | \index{regex} 42 | 43 | Another related tenet is ``YAGNI'': you aren't gonna need 44 | it. This acronym comes from a school of programming 45 | known as ``extreme programming'' (XP). Even if you don't 46 | adhere to all the XP principles, this idea is quite sound 47 | and well-founded: don't add any functionality until it is 48 | really needed. 49 | \index{YAGNI: you aren't gonna need it} 50 | 51 | Try to make your programs as clear as possible, and 52 | as simple as you can. Use more advanced concepts if 53 | you have to, but don't do it for the sake of showing how 54 | masterful you are. Don't try to be clever or, at least, 55 | don't be \emph{too} clever. 56 | 57 | Remember that code is not only used by the compiler, but 58 | is also by humans. Think about them. 59 | 60 | Think about the person who will have maintain your code. 61 | As some people like to put it: ``Always code as if the person 62 | who ends up maintaining your code is a violent psychopath 63 | who knows where you live.'' And, if nothing else will convince 64 | you, remember that the person maintaining your code might be 65 | you a year from now. You may not remember then 66 | how that neat trick you used really works. 67 | 68 | A final quote from Edsger Dijkstra on this subject: 69 | ``Simplicity is prerequisite for reliability.'' 70 | \index{Dijkstra, Edsger} 71 | \index{simplicity} 72 | 73 | \section{Dos and Don'ts} 74 | 75 | \begin{description} 76 | 77 | \item[Don't repeat yourself (DRY):] Avoid code duplication. 78 | If you have the same code in different places of your 79 | program, then something is most likely wrong. Maybe 80 | the repeated code should go into a loop or a separate 81 | subroutine, or perhaps even in a module or a library. 82 | Remember that copy and paste is a source of evil. 83 | \index{DRY: don't repeat yourself} 84 | 85 | \item[Don't reinvent the wheel:] Use existing libraries 86 | and modules when you can; it is likely that they have 87 | been thoroughly tested and will work better than the 88 | quick fix you're about to write. The Perl~6 ecosystem 89 | has a large and growing collection of software modules 90 | (see \url{modules.perl6.org}) that you can use in your 91 | programs. 92 | \index{reinventing the wheel} 93 | 94 | \item[Use meaningful identifiers] If your variables, 95 | subroutines, methods, classes, grammars, modules, 96 | and programs have sensible 97 | names that convey clearly what they are or what they do, 98 | then your code will be clearer and might need fewer 99 | comments. Very short names like \verb'$i' or \verb'$n' are 100 | usually fine for loop variables, but pretty much anything else needs 101 | a name that clearly explains what the content or the purpose is. 102 | Names like \verb'$array' or \verb'%hash' may have sometimes been 103 | used in some examples of this book to indicate more clearly 104 | the nature of the data structure, but they are not recommended in 105 | real-life programs. If your hash contains a collection of 106 | words, call it \verb'%words' or \verb'%word-list', not 107 | \verb'%hash'. The \% sigil indicates that it is a hash anyway. 108 | \index{meaningful identifier} 109 | 110 | \item[Make useful comments and avoid useless ones] A 111 | comment like this: 112 | \begin{verbatim} 113 | my $count = 1; # assigns 1 to $count 114 | \end{verbatim} 115 | is completely useless. In general, your comments should 116 | explain neither what your code is doing nor even how it is doing 117 | it (this should be obvious if your code is clear), but 118 | rather \emph{why} you are doing that: perhaps you should refer 119 | to a math theorem, a law of physics, a design decision, or 120 | a business rule. 121 | \index{comment} 122 | 123 | \item[Remove dead code and code scaffolding] Even when 124 | writing new code, you may at some point create variables 125 | that you don't use in the final version of your code. If so, 126 | remove them; don't let them distract the attention of your 127 | reader. If you modify an existing program, clean up the place 128 | after you've changed it. Remember the boy scout's rule: 129 | leave the place better and cleaner than you found it. 130 | \index{dead code} 131 | \index{scaffolding} 132 | 133 | \item[Test aggressively] Nobody can write any piece of 134 | significant software without having a number of initial 135 | bugs. Edsger Dijkstra is quoted as saying: ``If 136 | debugging is the process of removing software bugs, 137 | then programming must be the process of putting them in.'' 138 | It is unfortunately very true. Even though Dijkstra 139 | also said that ``Testing shows the presence, not the absence 140 | of bugs,'' testing is an essential part of software 141 | development. Write extensive test plans, use them often, and 142 | update them as the functionality evolves. See Section~\ref{test_module} 143 | (p.~\pageref{test_module}) for some automated testing tools. 144 | \index{test} 145 | \index{Dijkstra, Edsger} 146 | 147 | \item[Avoid premature optimization] In the words of Donald 148 | Knuth: ``Premature optimization is the source of all evil (or 149 | at least most of it) in programming.'' 150 | \index{premature optimization} 151 | \index{Knuth, Donald} 152 | 153 | \item[Don't use magical numbers:] Consider this: 154 | \begin{verbatim} 155 | my $time-left = 31536000; 156 | \end{verbatim} 157 | 158 | What is this 31,536,000 number coming out of nowhere? 159 | There's no way to know just by looking at this line 160 | of code. Compare with this: 161 | 162 | \begin{verbatim} 163 | my $secondsInAYear = 365 * 24 * 60 * 60; 164 | # ... 165 | my $time-left = $secondsInAYear; 166 | \end{verbatim} 167 | 168 | Isn't the second version clearer?\footnote{This calculation refers to a \emph{common} year (i.e. a non-leap calendar or civil year). It is not 169 | the same as various definitions of astronomical years, which are slightly less 170 | than a quarter of a day longer.} Well, to tell the 171 | truth, it would be even better to use a constant in 172 | such a case: 173 | \begin{verbatim} 174 | constant SECONDS-PER-YEAR = 365 * 24 * 60 * 60; 175 | \end{verbatim} 176 | \index{magical number} 177 | \index{constant} 178 | 179 | \item[Avoid hardcoded values:] Hard-coded values are bad. 180 | If you have to use some, define them as variables or constants 181 | at the beginning of your program, and use those variables or 182 | constants instead. Hard-coded file paths are especially bad. If you 183 | have to use some, use some variables with relative paths: 184 | \begin{verbatim} 185 | my $base-dir = '/path/to/application/data'; 186 | my $input-dir = "$base-dir/INPUT"; 187 | my $result-dir = "$base-dir/RESULT"; 188 | my $temp-dir = "$base-dir/TEMP"; 189 | my $log-dir = "$base-dir/LOG"; 190 | \end{verbatim} 191 | At least, if the path must change, you have to change only 192 | the top code line. 193 | \index{hard-coded value} 194 | 195 | \item[Don't ignore errors returned by subroutines or built-in 196 | functions:] Not all return values are useful; for example, we 197 | usually don't check the return value of a print statement, but 198 | that's usually fine because we are interested in the side effect, 199 | the fact of printing something out to the screen or to a file, 200 | rather than in the return value. In most other cases, you need 201 | to know if something went wrong in order to take steps to either 202 | recover from the error condition, if possible, or to abort the 203 | program gracefully (e.g., with an informative error message) if 204 | the error is too serious for the program to continue. 205 | \index{error!ignoring} 206 | 207 | \item[Format your code clearly and consistently] The compiler 208 | might not care about code indentation, but human readers do. 209 | Your code formatting should help clarify the structure and 210 | control flow of your programs. 211 | \index{indentation} 212 | 213 | \item[Be nice and have fun.] 214 | \index{fun} 215 | 216 | \end{description} 217 | 218 | \section{Use Idioms} 219 | \index{idiom} 220 | 221 | Any language has its own ``best practice'' methods of use. 222 | These are the idioms that experienced programmers use, ways of doing 223 | things that have become preferred over time. These idioms are important. 224 | They protect you from reinventing the wheel. They are also what 225 | experienced users expect to read; they are familiar 226 | and enable you to focus on the overall code design rather than 227 | get bogged down in detailed code concerns. They often formalize 228 | patterns that avoid common mistakes or bugs. 229 | 230 | Even though Perl~6 is a relatively new language, a number of such 231 | idioms have become honed over time. Here are a few of these 232 | idiomatic constructs~\footnote{When two solutions are suggested, 233 | the second one is usually the more idiomatic one.}. 234 | \index{idiomatic Perl~6} 235 | 236 | 237 | \begin{description} 238 | \item[Creating a hash from a list of keys and a list of values] Using slices: 239 | \index{hash slice} 240 | 241 | \begin{verbatim} 242 | my %hash; %hash{@keys} = @values; 243 | \end{verbatim} 244 | 245 | Using the \emph{zip} operator and a metaoperator with the pair constructor: 246 | \index{zip operator} 247 | \index{metaoperator} 248 | \index{operator!zip} 249 | 250 | \begin{verbatim} 251 | my %hash = @keys Z=> @values; 252 | \end{verbatim} 253 | 254 | For existence tests, the hash values only need to be true. Here is 255 | a good way to create a hash from a list of keys: 256 | \begin{verbatim} 257 | my %exists = @keys X=> True; 258 | \end{verbatim} 259 | 260 | Or, better yet, use a set: 261 | \begin{verbatim} 262 | my $exists = @keys.Set; 263 | say "exists" if $exists{$object}; 264 | \end{verbatim} 265 | 266 | \item[Making mandatory attributes (or subroutine parameters):] 267 | This is a nice way of making a mandatory attribute in a class: 268 | \index{mandatory attribute} 269 | \begin{verbatim} 270 | has $.attr = die "The 'attr' attribute is mandatory"; 271 | \end{verbatim} 272 | This code uses the default value mechanism: if a value is supplied, 273 | then the code for the default value does not run. If no value is 274 | supplied, then the code dies with the appropriate error message. 275 | The same mechanism can be used for subroutine parameters. 276 | 277 | Or you could use the \verb'is required' trait: 278 | 279 | \begin{verbatim} 280 | > class A { has $.a is required }; 281 | > A.new; 282 | The attribute '$!a' is required, 283 | but you did not provide a value for it. 284 | \end{verbatim} 285 | 286 | You can even pass a explanatory message: 287 | 288 | \begin{verbatim} 289 | > class A { has $.a is required("We need it") }; 290 | > A.new; 291 | The attribute '$!a' is required because We need it, 292 | but you did not provide a value for it. 293 | \end{verbatim} 294 | 295 | \item[Iterating over the subscripts of an array] The first 296 | solution that comes to mind might be: 297 | \index{end method} 298 | 299 | \begin{verbatim} 300 | for 0 .. @array.end -> $i {...} 301 | \end{verbatim} 302 | 303 | That's fine, but this is probably even better: 304 | \index{keys function or method} 305 | 306 | \begin{verbatim} 307 | for @array.keys -> $i {...} 308 | \end{verbatim} 309 | 310 | \item[Iterating over the subscripts and values of an array] 311 | The \verb'.kv' method, in combination with a pointy block 312 | taking two parameters, allows you to easily iterate over an 313 | array: 314 | \index{kv function or method} 315 | 316 | \begin{verbatim} 317 | for @array.kv -> $i, $value {...} 318 | \end{verbatim} 319 | 320 | 321 | \item[Printing the number of items in an array] Two possible 322 | solutions: 323 | \index{elems function or method} 324 | 325 | \begin{verbatim} 326 | say +@array; 327 | # or: 328 | say @array.elems; 329 | \end{verbatim} 330 | 331 | \item[Do something every third time] Use the \verb'%%' 332 | divisibility operator on the loop variable: 333 | \index{divisibility} 334 | \begin{verbatim} 335 | if $i %% 3 {...} 336 | \end{verbatim} 337 | 338 | \item[Do something \emph{n} times:] Use the right-open range operator: 339 | \index{range operator} 340 | 341 | \begin{verbatim} 342 | for 0 ..^ $n {...} 343 | # or, simpler: 344 | for ^$n {...} 345 | \end{verbatim} 346 | 347 | \item[Split a string into words (splitting on space):] 348 | A method call without an explicit invocant always uses 349 | the \verb'$_' topical variable as an implicit invocant. Thus, 350 | assuming the string has been topicalized into \verb'$_': 351 | \index{split function or method} 352 | \index{words function or method} 353 | \index{topical variable} 354 | \index{invocant} 355 | 356 | \begin{verbatim} 357 | @words = .split(/\s+/); 358 | # or, simpler: 359 | @words = .words; 360 | \end{verbatim} 361 | 362 | \item[An infinite loop] A {\tt loop} statement with no parentheses 363 | and no argument loops forever: 364 | \index{infinite loop} 365 | \index{loop!infinite} 366 | 367 | \begin{verbatim} 368 | while True {...} 369 | # or, more idiomatic: 370 | loop {...} 371 | \end{verbatim} 372 | 373 | Of course, the body of the {\tt loop} statement must have some 374 | kind of flow control statement to exit the loop at some point. 375 | 376 | \item[Returning the unique elements of a list] The {\tt unique} 377 | method removes duplicates from the input list: 378 | \index{unique function} 379 | 380 | \begin{verbatim} 381 | return @array.unique; 382 | \end{verbatim} 383 | 384 | Or, if you know that your list is sorted, you can use the 385 | {\tt squish} function (which removes adjacent duplicates). 386 | \index{squish function} 387 | 388 | \item[Adding up the items of a list] Use the {\tt reduce} 389 | function or the reduction metaoperator: 390 | \index{reduce function} 391 | \index{reduction operator} 392 | \index{sum function or method} 393 | 394 | \begin{verbatim} 395 | my $sum = @a.reduce(* + *); 396 | # or, simpler: 397 | my $sum = [+] @a; 398 | # or yet simpler, using the sum built-in: 399 | my $sum = @a.sum; 400 | \end{verbatim} 401 | 402 | \item[Swapping two variables] Use the \verb'.=' mutating 403 | method call with the \verb'reverse' function: 404 | \begin{verbatim} 405 | ( $x, $y ) = $y, $x; 406 | # or: 407 | ( $x, $y ) .= reverse; # equivalent to: ($x, $y) = ($x, $y).reverse 408 | \end{verbatim} 409 | \index{swapping variables} 410 | 411 | \item[Generating random integers between 2 and 6] Use the \verb'..' 412 | range operator and the {\tt pick} method: 413 | \index{pick function or method} 414 | \index{random number} 415 | \begin{verbatim} 416 | $z = 2 + Int(5.rand); 417 | # or, better: 418 | $z = (2..6).pick; 419 | \end{verbatim} 420 | 421 | \item[Count by steps of 3 in an infinite loop] Use the \verb'...' 422 | sequence operator with the ``*'' whatever star operator and 423 | a pointy block: 424 | \index{whatever operator} 425 | \index{sequence operator} 426 | 427 | \begin{verbatim} 428 | for 3, * + 3 ... * -> $n {...} 429 | # or: 430 | for 3, 6, 9 ... * -> $n {...} 431 | \end{verbatim} 432 | 433 | \item[Loop on a range of values, discounting the range limits:] Use 434 | the open range operator: 435 | \index{range operator} 436 | 437 | \begin{verbatim} 438 | for ($start+1) .. ($end-1) -> $i {...} 439 | # or, better: 440 | for $start ^..^ $end -> $i {...} 441 | \end{verbatim} 442 | \end{description} 443 | 444 | \section{What's Next?} 445 | 446 | A book like this one can't tell you everything about programming, 447 | nor about Perl~6. At this point, you should know how to write a 448 | program to solve an average-difficulty problem, but a lot of work 449 | has been done in the last decades to solve harder problems. So 450 | where should you go from here? 451 | 452 | Read books about algorithmics, the science of algorithms. Many good 453 | books exist on the subject, but I especially recommend the following 454 | two (you should be aware, though, that they are not easy): 455 | \begin{itemize} 456 | \item Thomas H. Cormen, Charles E. Leiserson, Ronald L. Rivest, 457 | and Clifford Stein, \emph{Introduction to 458 | Algorithms}, The MIT Press 459 | \item Donald Knuth, \emph{The Art of Computer Programming}, Addison Wesley 460 | (many volumes, many editions). 461 | \end{itemize} 462 | 463 | Read other books about programming, even if they 464 | target other programming languages or no specific programming 465 | language. They're likely to have a 466 | different approach on various points; this will offer you a 467 | different perspective and perhaps better comprehension, and 468 | will complement what you have read here. 469 | Read tutorials, articles, blogs, and forums about programming. 470 | Participate when you can. Read the \emph{Introduction to 471 | Perl~6} which exists in eight different languages as of 472 | this writing (\url{http://perl6intro.com/}). Read the 473 | official Perl~6 documentation (\url{https://docs.perl6.org}). 474 | \index{Perl~6 documentation} 475 | 476 | This book has more than a thousand code examples, which is quite 477 | a lot, but may not be sufficient if you really want to learn more. 478 | You should also read code samples written by others. Look for 479 | open source libraries or modules and try to understand what they 480 | do and how they do it. Try to use them. 481 | 482 | Having said that, I should stress that you can read as many books 483 | as you want about the theory of swimming, but you'll never know 484 | swimming until you really get around to doing it. The same is true 485 | about learning to program and learning a programming 486 | language. Write new code. Modify existing examples, and see what 487 | happens. Try new things. Go ahead, be bold, dive into the pool and 488 | swim. The bottom line is: you will really learn by doing. 489 | 490 | Learning the art of programming is great fun. Enjoy it! 491 | \index{fun} 492 | 493 | -------------------------------------------------------------------------------- /book/figs/450px-International_Morse_Code.svg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LaurentRosenfeld/thinkperl6/8223c17d3437475e4e9602699b9348ee53c24c04/book/figs/450px-International_Morse_Code.svg.png -------------------------------------------------------------------------------- /book/figs/International_Morse_Code.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LaurentRosenfeld/thinkperl6/8223c17d3437475e4e9602699b9348ee53c24c04/book/figs/International_Morse_Code.PNG -------------------------------------------------------------------------------- /book/figs/fibonacci.pfi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LaurentRosenfeld/thinkperl6/8223c17d3437475e4e9602699b9348ee53c24c04/book/figs/fibonacci.pfi -------------------------------------------------------------------------------- /book/figs/fibonacci.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LaurentRosenfeld/thinkperl6/8223c17d3437475e4e9602699b9348ee53c24c04/book/figs/fibonacci.png -------------------------------------------------------------------------------- /book/figs/figure_heap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LaurentRosenfeld/thinkperl6/8223c17d3437475e4e9602699b9348ee53c24c04/book/figs/figure_heap.png -------------------------------------------------------------------------------- /book/figs/figure_heap2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LaurentRosenfeld/thinkperl6/8223c17d3437475e4e9602699b9348ee53c24c04/book/figs/figure_heap2.png -------------------------------------------------------------------------------- /book/figs/hash1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LaurentRosenfeld/thinkperl6/8223c17d3437475e4e9602699b9348ee53c24c04/book/figs/hash1.pdf -------------------------------------------------------------------------------- /book/figs/hash1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LaurentRosenfeld/thinkperl6/8223c17d3437475e4e9602699b9348ee53c24c04/book/figs/hash1.png -------------------------------------------------------------------------------- /book/figs/point2D.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LaurentRosenfeld/thinkperl6/8223c17d3437475e4e9602699b9348ee53c24c04/book/figs/point2D.png -------------------------------------------------------------------------------- /book/figs/reassignment.pfi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LaurentRosenfeld/thinkperl6/8223c17d3437475e4e9602699b9348ee53c24c04/book/figs/reassignment.pfi -------------------------------------------------------------------------------- /book/figs/reassignment.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LaurentRosenfeld/thinkperl6/8223c17d3437475e4e9602699b9348ee53c24c04/book/figs/reassignment.png -------------------------------------------------------------------------------- /book/figs/rectangle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LaurentRosenfeld/thinkperl6/8223c17d3437475e4e9602699b9348ee53c24c04/book/figs/rectangle.png -------------------------------------------------------------------------------- /book/figs/rectangle2.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LaurentRosenfeld/thinkperl6/8223c17d3437475e4e9602699b9348ee53c24c04/book/figs/rectangle2.pdf -------------------------------------------------------------------------------- /book/figs/stack.eps: -------------------------------------------------------------------------------- 1 | %!PS-Adobe-3.0 EPSF-3.0 2 | %%Title: stack.fig 3 | %%Creator: fig2dev Version 3.2 Patchlevel 5e 4 | %%CreationDate: Mon Jul 27 11:38:05 2015 5 | %%BoundingBox: 0 0 284 141 6 | %Magnification: 1.0000 7 | %%EndComments 8 | %%BeginProlog 9 | /$F2psDict 200 dict def 10 | $F2psDict begin 11 | $F2psDict /mtrx matrix put 12 | /col-1 {0 setgray} bind def 13 | /col0 {0.000 0.000 0.000 srgb} bind def 14 | /col1 {0.000 0.000 1.000 srgb} bind def 15 | /col2 {0.000 1.000 0.000 srgb} bind def 16 | /col3 {0.000 1.000 1.000 srgb} bind def 17 | /col4 {1.000 0.000 0.000 srgb} bind def 18 | /col5 {1.000 0.000 1.000 srgb} bind def 19 | /col6 {1.000 1.000 0.000 srgb} bind def 20 | /col7 {1.000 1.000 1.000 srgb} bind def 21 | /col8 {0.000 0.000 0.560 srgb} bind def 22 | /col9 {0.000 0.000 0.690 srgb} bind def 23 | /col10 {0.000 0.000 0.820 srgb} bind def 24 | /col11 {0.530 0.810 1.000 srgb} bind def 25 | /col12 {0.000 0.560 0.000 srgb} bind def 26 | /col13 {0.000 0.690 0.000 srgb} bind def 27 | /col14 {0.000 0.820 0.000 srgb} bind def 28 | /col15 {0.000 0.560 0.560 srgb} bind def 29 | /col16 {0.000 0.690 0.690 srgb} bind def 30 | /col17 {0.000 0.820 0.820 srgb} bind def 31 | /col18 {0.560 0.000 0.000 srgb} bind def 32 | /col19 {0.690 0.000 0.000 srgb} bind def 33 | /col20 {0.820 0.000 0.000 srgb} bind def 34 | /col21 {0.560 0.000 0.560 srgb} bind def 35 | /col22 {0.690 0.000 0.690 srgb} bind def 36 | /col23 {0.820 0.000 0.820 srgb} bind def 37 | /col24 {0.500 0.190 0.000 srgb} bind def 38 | /col25 {0.630 0.250 0.000 srgb} bind def 39 | /col26 {0.750 0.380 0.000 srgb} bind def 40 | /col27 {1.000 0.500 0.500 srgb} bind def 41 | /col28 {1.000 0.630 0.630 srgb} bind def 42 | /col29 {1.000 0.750 0.750 srgb} bind def 43 | /col30 {1.000 0.880 0.880 srgb} bind def 44 | /col31 {1.000 0.840 0.000 srgb} bind def 45 | 46 | end 47 | 48 | /cp {closepath} bind def 49 | /ef {eofill} bind def 50 | /gr {grestore} bind def 51 | /gs {gsave} bind def 52 | /sa {save} bind def 53 | /rs {restore} bind def 54 | /l {lineto} bind def 55 | /m {moveto} bind def 56 | /rm {rmoveto} bind def 57 | /n {newpath} bind def 58 | /s {stroke} bind def 59 | /sh {show} bind def 60 | /slc {setlinecap} bind def 61 | /slj {setlinejoin} bind def 62 | /slw {setlinewidth} bind def 63 | /srgb {setrgbcolor} bind def 64 | /rot {rotate} bind def 65 | /sc {scale} bind def 66 | /sd {setdash} bind def 67 | /ff {findfont} bind def 68 | /sf {setfont} bind def 69 | /scf {scalefont} bind def 70 | /sw {stringwidth} bind def 71 | /tr {translate} bind def 72 | /tnt {dup dup currentrgbcolor 73 | 4 -2 roll dup 1 exch sub 3 -1 roll mul add 74 | 4 -2 roll dup 1 exch sub 3 -1 roll mul add 75 | 4 -2 roll dup 1 exch sub 3 -1 roll mul add srgb} 76 | bind def 77 | /shd {dup dup currentrgbcolor 4 -2 roll mul 4 -2 roll mul 78 | 4 -2 roll mul srgb} bind def 79 | /$F2psBegin {$F2psDict begin /$F2psEnteredState save def} def 80 | /$F2psEnd {$F2psEnteredState restore end} def 81 | 82 | /pageheader { 83 | save 84 | newpath 0 141 moveto 0 0 lineto 284 0 lineto 284 141 lineto closepath clip newpath 85 | -14.6 198.7 translate 86 | 1 -1 scale 87 | $F2psBegin 88 | 10 setmiterlimit 89 | 0 slj 0 slc 90 | 0.06000 0.06000 sc 91 | } bind def 92 | /pagefooter { 93 | $F2psEnd 94 | restore 95 | } bind def 96 | %%EndProlog 97 | pageheader 98 | % 99 | % Fig objects follow 100 | % 101 | % 102 | % here starts figure with depth 51 103 | % Polyline 104 | 0 slj 105 | 0 slc 106 | 7.500 slw 107 | n 1424 2925 m 4950 2925 l 4950 3300 l 1424 3300 l 108 | cp gs col7 0.90 shd ef gr gs col0 s gr 109 | % Polyline 110 | n 1425 1800 m 4950 1800 l 4950 2775 l 1425 2775 l 111 | cp gs col7 0.90 shd ef gr gs col0 s gr 112 | % Polyline 113 | n 1425 975 m 4950 975 l 4950 1650 l 1425 1650 l 114 | cp gs col7 0.90 shd ef gr gs col0 s gr 115 | % Polyline 116 | gs clippath 117 | 2338 2302 m 2490 2302 l 2490 2242 l 2338 2242 l 2338 2242 l 2458 2272 l 2338 2302 l cp 118 | eoclip 119 | n 2100 2272 m 120 | 2475 2272 l gs col0 s gr gr 121 | 122 | % arrowhead 123 | n 2338 2302 m 2458 2272 l 2338 2242 l col0 s 124 | % Polyline 125 | gs clippath 126 | 2338 2602 m 2490 2602 l 2490 2542 l 2338 2542 l 2338 2542 l 2458 2572 l 2338 2602 l cp 127 | eoclip 128 | n 2100 2572 m 129 | 2475 2572 l gs col0 s gr gr 130 | 131 | % arrowhead 132 | n 2338 2602 m 2458 2572 l 2338 2542 l col0 s 133 | % Polyline 134 | gs clippath 135 | 2338 2002 m 2490 2002 l 2490 1942 l 2338 1942 l 2338 1942 l 2458 1972 l 2338 2002 l cp 136 | eoclip 137 | n 2100 1972 m 138 | 2475 1972 l gs col0 s gr gr 139 | 140 | % arrowhead 141 | n 2338 2002 m 2458 1972 l 2338 1942 l col0 s 142 | % Polyline 143 | gs clippath 144 | 2338 1477 m 2490 1477 l 2490 1417 l 2338 1417 l 2338 1417 l 2458 1447 l 2338 1477 l cp 145 | eoclip 146 | n 2100 1447 m 147 | 2475 1447 l gs col0 s gr gr 148 | 149 | % arrowhead 150 | n 2338 1477 m 2458 1447 l 2338 1417 l col0 s 151 | % Polyline 152 | gs clippath 153 | 2338 1177 m 2490 1177 l 2490 1117 l 2338 1117 l 2338 1117 l 2458 1147 l 2338 1177 l cp 154 | eoclip 155 | n 2100 1147 m 156 | 2475 1147 l gs col0 s gr gr 157 | 158 | % arrowhead 159 | n 2338 1177 m 2458 1147 l 2338 1117 l col0 s 160 | % Polyline 161 | gs clippath 162 | 2330 3127 m 2482 3127 l 2482 3067 l 2330 3067 l 2330 3067 l 2450 3097 l 2330 3127 l cp 163 | eoclip 164 | n 2092 3097 m 165 | 2467 3097 l gs col0 s gr gr 166 | 167 | % arrowhead 168 | n 2330 3127 m 2450 3097 l 2330 3067 l col0 s 169 | /Helvetica ff 183.33 scf sf 170 | 2025 1200 m 171 | gs 1 -1 sc (line1) dup sw pop neg 0 rm col0 sh gr 172 | /Helvetica ff 183.33 scf sf 173 | 2025 1500 m 174 | gs 1 -1 sc (line2) dup sw pop neg 0 rm col0 sh gr 175 | /Helvetica ff 183.33 scf sf 176 | 2550 1500 m 177 | gs 1 -1 sc ('tiddle bang.') col0 sh gr 178 | /Helvetica ff 183.33 scf sf 179 | 2025 2025 m 180 | gs 1 -1 sc (part1) dup sw pop neg 0 rm col0 sh gr 181 | /Helvetica ff 183.33 scf sf 182 | 2025 2325 m 183 | gs 1 -1 sc (part2) dup sw pop neg 0 rm col0 sh gr 184 | /Helvetica ff 183.33 scf sf 185 | 2025 2625 m 186 | gs 1 -1 sc (cat) dup sw pop neg 0 rm col0 sh gr 187 | /Helvetica ff 183.33 scf sf 188 | 2017 3150 m 189 | gs 1 -1 sc (bruce) dup sw pop neg 0 rm col0 sh gr 190 | /Helvetica ff 183.33 scf sf 191 | 2550 1200 m 192 | gs 1 -1 sc ('Bing tiddle ') col0 sh gr 193 | /Helvetica ff 183.33 scf sf 194 | 2550 2025 m 195 | gs 1 -1 sc ('Bing tiddle ') col0 sh gr 196 | /Helvetica ff 183.33 scf sf 197 | 2550 2325 m 198 | gs 1 -1 sc ('tiddle bang.') col0 sh gr 199 | /Helvetica ff 183.33 scf sf 200 | 2550 2625 m 201 | gs 1 -1 sc ('Bing tiddle tiddle bang.') col0 sh gr 202 | /Helvetica ff 183.33 scf sf 203 | 2550 3150 m 204 | gs 1 -1 sc ('Bing tiddle tiddle bang.') col0 sh gr 205 | /Helvetica ff 183.33 scf sf 206 | 1275 2325 m 207 | gs 1 -1 sc (cat_twice) dup sw pop neg 0 rm col0 sh gr 208 | /Helvetica ff 183.33 scf sf 209 | 1275 3150 m 210 | gs 1 -1 sc (print_twice) dup sw pop neg 0 rm col0 sh gr 211 | % __main__ 212 | /Helvetica ff 183.33 scf sf 213 | 1275 1350 m 214 | gs 1 -1 sc (__main__) dup sw pop neg 0 rm col0 sh gr 215 | % here ends figure; 216 | pagefooter 217 | showpage 218 | %%Trailer 219 | %EOF 220 | -------------------------------------------------------------------------------- /book/figs/stack.fig: -------------------------------------------------------------------------------- 1 | #FIG 3.2 Produced by xfig version 3.2.5c 2 | Landscape 3 | Center 4 | Inches 5 | Letter 6 | 100.00 7 | Single 8 | -2 9 | 1200 2 10 | 6 2100 1897 2475 2647 11 | 2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2 12 | 0 0 1.00 60.00 120.00 13 | 2100 2272 2475 2272 14 | 2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2 15 | 0 0 1.00 60.00 120.00 16 | 2100 2572 2475 2572 17 | 2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2 18 | 0 0 1.00 60.00 120.00 19 | 2100 1972 2475 1972 20 | -6 21 | 2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2 22 | 0 0 1.00 60.00 120.00 23 | 2100 1447 2475 1447 24 | 2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2 25 | 0 0 1.00 60.00 120.00 26 | 2100 1147 2475 1147 27 | 2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2 28 | 0 0 1.00 60.00 120.00 29 | 2092 3097 2467 3097 30 | 2 2 0 1 0 7 51 0 18 0.000 0 0 -1 0 0 5 31 | 1424 2925 4950 2925 4950 3300 1424 3300 1424 2925 32 | 2 2 0 1 0 7 51 0 18 0.000 0 0 -1 0 0 5 33 | 1425 1800 4950 1800 4950 2775 1425 2775 1425 1800 34 | 2 2 0 1 0 7 51 0 18 0.000 0 0 -1 0 0 5 35 | 1425 975 4950 975 4950 1650 1425 1650 1425 975 36 | 4 2 0 50 0 16 11 0.0000 4 135 450 2025 1200 line1\001 37 | 4 2 0 50 0 16 11 0.0000 4 135 450 2025 1500 line2\001 38 | 4 0 0 50 0 16 11 0.0000 4 165 1260 2550 1500 'tiddle bang.'\001 39 | 4 2 0 50 0 16 11 0.0000 4 165 450 2025 2025 part1\001 40 | 4 2 0 50 0 16 11 0.0000 4 165 450 2025 2325 part2\001 41 | 4 2 0 50 0 16 11 0.0000 4 120 270 2025 2625 cat\001 42 | 4 2 0 50 0 16 11 0.0000 4 135 450 2017 3150 bruce\001 43 | 4 0 0 50 0 16 11 0.0000 4 165 1260 2550 1200 'Bing tiddle '\001 44 | 4 0 0 50 0 16 11 0.0000 4 165 1260 2550 2025 'Bing tiddle '\001 45 | 4 0 0 50 0 16 11 0.0000 4 165 1260 2550 2325 'tiddle bang.'\001 46 | 4 0 0 50 0 16 11 0.0000 4 165 2340 2550 2625 'Bing tiddle tiddle bang.'\001 47 | 4 0 0 50 0 16 11 0.0000 4 165 2340 2550 3150 'Bing tiddle tiddle bang.'\001 48 | 4 2 0 50 0 16 11 0.0000 4 135 810 1275 2325 cat_twice\001 49 | 4 2 0 50 0 16 11 0.0000 4 150 990 1275 3150 print_twice\001 50 | # __main__ 51 | 4 2 0 50 0 16 11 0.0000 4 135 720 1275 1350 __main__\001 52 | -------------------------------------------------------------------------------- /book/figs/stack.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LaurentRosenfeld/thinkperl6/8223c17d3437475e4e9602699b9348ee53c24c04/book/figs/stack.pdf -------------------------------------------------------------------------------- /book/figs/stack2.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LaurentRosenfeld/thinkperl6/8223c17d3437475e4e9602699b9348ee53c24c04/book/figs/stack2.pdf -------------------------------------------------------------------------------- /book/figs/stack2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LaurentRosenfeld/thinkperl6/8223c17d3437475e4e9602699b9348ee53c24c04/book/figs/stack2.png -------------------------------------------------------------------------------- /book/figs/stack3.eps: -------------------------------------------------------------------------------- 1 | %!PS-Adobe-3.0 EPSF-3.0 2 | %%Title: stack3.fig 3 | %%Creator: fig2dev Version 3.2 Patchlevel 5e 4 | %%CreationDate: Mon Jul 27 11:39:42 2015 5 | %%BoundingBox: 0 0 319 150 6 | %Magnification: 1.0000 7 | %%EndComments 8 | %%BeginProlog 9 | /$F2psDict 200 dict def 10 | $F2psDict begin 11 | $F2psDict /mtrx matrix put 12 | /col-1 {0 setgray} bind def 13 | /col0 {0.000 0.000 0.000 srgb} bind def 14 | /col1 {0.000 0.000 1.000 srgb} bind def 15 | /col2 {0.000 1.000 0.000 srgb} bind def 16 | /col3 {0.000 1.000 1.000 srgb} bind def 17 | /col4 {1.000 0.000 0.000 srgb} bind def 18 | /col5 {1.000 0.000 1.000 srgb} bind def 19 | /col6 {1.000 1.000 0.000 srgb} bind def 20 | /col7 {1.000 1.000 1.000 srgb} bind def 21 | /col8 {0.000 0.000 0.560 srgb} bind def 22 | /col9 {0.000 0.000 0.690 srgb} bind def 23 | /col10 {0.000 0.000 0.820 srgb} bind def 24 | /col11 {0.530 0.810 1.000 srgb} bind def 25 | /col12 {0.000 0.560 0.000 srgb} bind def 26 | /col13 {0.000 0.690 0.000 srgb} bind def 27 | /col14 {0.000 0.820 0.000 srgb} bind def 28 | /col15 {0.000 0.560 0.560 srgb} bind def 29 | /col16 {0.000 0.690 0.690 srgb} bind def 30 | /col17 {0.000 0.820 0.820 srgb} bind def 31 | /col18 {0.560 0.000 0.000 srgb} bind def 32 | /col19 {0.690 0.000 0.000 srgb} bind def 33 | /col20 {0.820 0.000 0.000 srgb} bind def 34 | /col21 {0.560 0.000 0.560 srgb} bind def 35 | /col22 {0.690 0.000 0.690 srgb} bind def 36 | /col23 {0.820 0.000 0.820 srgb} bind def 37 | /col24 {0.500 0.190 0.000 srgb} bind def 38 | /col25 {0.630 0.250 0.000 srgb} bind def 39 | /col26 {0.750 0.380 0.000 srgb} bind def 40 | /col27 {1.000 0.500 0.500 srgb} bind def 41 | /col28 {1.000 0.630 0.630 srgb} bind def 42 | /col29 {1.000 0.750 0.750 srgb} bind def 43 | /col30 {1.000 0.880 0.880 srgb} bind def 44 | /col31 {1.000 0.840 0.000 srgb} bind def 45 | 46 | end 47 | 48 | /cp {closepath} bind def 49 | /ef {eofill} bind def 50 | /gr {grestore} bind def 51 | /gs {gsave} bind def 52 | /sa {save} bind def 53 | /rs {restore} bind def 54 | /l {lineto} bind def 55 | /m {moveto} bind def 56 | /rm {rmoveto} bind def 57 | /n {newpath} bind def 58 | /s {stroke} bind def 59 | /sh {show} bind def 60 | /slc {setlinecap} bind def 61 | /slj {setlinejoin} bind def 62 | /slw {setlinewidth} bind def 63 | /srgb {setrgbcolor} bind def 64 | /rot {rotate} bind def 65 | /sc {scale} bind def 66 | /sd {setdash} bind def 67 | /ff {findfont} bind def 68 | /sf {setfont} bind def 69 | /scf {scalefont} bind def 70 | /sw {stringwidth} bind def 71 | /tr {translate} bind def 72 | /tnt {dup dup currentrgbcolor 73 | 4 -2 roll dup 1 exch sub 3 -1 roll mul add 74 | 4 -2 roll dup 1 exch sub 3 -1 roll mul add 75 | 4 -2 roll dup 1 exch sub 3 -1 roll mul add srgb} 76 | bind def 77 | /shd {dup dup currentrgbcolor 4 -2 roll mul 4 -2 roll mul 78 | 4 -2 roll mul srgb} bind def 79 | /$F2psBegin {$F2psDict begin /$F2psEnteredState save def} def 80 | /$F2psEnd {$F2psEnteredState restore end} def 81 | 82 | /pageheader { 83 | save 84 | newpath 0 150 moveto 0 0 lineto 319 0 lineto 319 150 lineto closepath clip newpath 85 | -48.2 176.2 translate 86 | 1 -1 scale 87 | $F2psBegin 88 | 10 setmiterlimit 89 | 0 slj 0 slc 90 | 0.06000 0.06000 sc 91 | } bind def 92 | /pagefooter { 93 | $F2psEnd 94 | restore 95 | } bind def 96 | %%EndProlog 97 | pageheader 98 | % 99 | % Fig objects follow 100 | % 101 | % 102 | % here starts figure with depth 51 103 | % Polyline 104 | 0 slj 105 | 0 slc 106 | 7.500 slw 107 | n 1800 975 m 5700 975 l 5700 1350 l 1800 1350 l 108 | cp gs col7 0.90 shd ef gr gs col0 s gr 109 | % Polyline 110 | n 1800 1500 m 5700 1500 l 5700 1875 l 1800 1875 l 111 | cp gs col7 0.90 shd ef gr gs col0 s gr 112 | % Polyline 113 | n 1800 2025 m 5700 2025 l 5700 2400 l 1800 2400 l 114 | cp gs col7 0.90 shd ef gr gs col0 s gr 115 | % Polyline 116 | n 1800 2550 m 5700 2550 l 5700 2925 l 1800 2925 l 117 | cp gs col7 0.90 shd ef gr gs col0 s gr 118 | % Polyline 119 | n 1800 450 m 5700 450 l 5700 825 l 1800 825 l 120 | cp gs col7 0.90 shd ef gr gs col0 s gr 121 | % Polyline 122 | gs clippath 123 | 2413 1177 m 2565 1177 l 2565 1117 l 2413 1117 l 2413 1117 l 2533 1147 l 2413 1177 l cp 124 | eoclip 125 | n 2175 1147 m 126 | 2550 1147 l gs col0 s gr gr 127 | 128 | % arrowhead 129 | n 2413 1177 m 2533 1147 l 2413 1117 l col0 s 130 | % Polyline 131 | gs clippath 132 | 3913 1177 m 4065 1177 l 4065 1117 l 3913 1117 l 3913 1117 l 4033 1147 l 3913 1177 l cp 133 | eoclip 134 | n 3675 1147 m 135 | 4050 1147 l gs col0 s gr gr 136 | 137 | % arrowhead 138 | n 3913 1177 m 4033 1147 l 3913 1117 l col0 s 139 | % Polyline 140 | gs clippath 141 | 3913 1702 m 4065 1702 l 4065 1642 l 3913 1642 l 3913 1642 l 4033 1672 l 3913 1702 l cp 142 | eoclip 143 | n 3675 1672 m 144 | 4050 1672 l gs col0 s gr gr 145 | 146 | % arrowhead 147 | n 3913 1702 m 4033 1672 l 3913 1642 l col0 s 148 | % Polyline 149 | gs clippath 150 | 3913 2227 m 4065 2227 l 4065 2167 l 3913 2167 l 3913 2167 l 4033 2197 l 3913 2227 l cp 151 | eoclip 152 | n 3675 2197 m 153 | 4050 2197 l gs col0 s gr gr 154 | 155 | % arrowhead 156 | n 3913 2227 m 4033 2197 l 3913 2167 l col0 s 157 | % Arc 158 | gs clippath 159 | 5839 2262 m 5694 2216 l 5676 2274 l 5821 2319 l 5821 2319 l 5716 2255 l 5839 2262 l cp 160 | eoclip 161 | n 5700.0 2475.0 225.0 90.0000 -90.0000 arcn 162 | gs col0 s gr 163 | gr 164 | 165 | % arrowhead 166 | n 5839 2262 m 5716 2255 l 5821 2319 l col0 s 167 | % Arc 168 | gs clippath 169 | 5839 1737 m 5694 1691 l 5676 1749 l 5821 1794 l 5821 1794 l 5716 1730 l 5839 1737 l cp 170 | eoclip 171 | n 5700.0 1950.0 225.0 90.0000 -90.0000 arcn 172 | gs col0 s gr 173 | gr 174 | 175 | % arrowhead 176 | n 5839 1737 m 5716 1730 l 5821 1794 l col0 s 177 | % Arc 178 | gs clippath 179 | 5839 687 m 5694 641 l 5676 699 l 5821 744 l 5821 744 l 5716 680 l 5839 687 l cp 180 | eoclip 181 | n 5700.0 900.0 225.0 90.0000 -90.0000 arcn 182 | gs col0 s gr 183 | gr 184 | 185 | % arrowhead 186 | n 5839 687 m 5716 680 l 5821 744 l col0 s 187 | % Arc 188 | gs clippath 189 | 5839 1212 m 5694 1166 l 5676 1224 l 5821 1269 l 5821 1269 l 5716 1205 l 5839 1212 l cp 190 | eoclip 191 | n 5700.0 1425.0 225.0 90.0000 -90.0000 arcn 192 | gs col0 s gr 193 | gr 194 | 195 | % arrowhead 196 | n 5839 1212 m 5716 1205 l 5821 1269 l col0 s 197 | % Polyline 198 | gs clippath 199 | 2413 1702 m 2565 1702 l 2565 1642 l 2413 1642 l 2413 1642 l 2533 1672 l 2413 1702 l cp 200 | eoclip 201 | n 2175 1672 m 202 | 2550 1672 l gs col0 s gr gr 203 | 204 | % arrowhead 205 | n 2413 1702 m 2533 1672 l 2413 1642 l col0 s 206 | % Polyline 207 | gs clippath 208 | 2413 2227 m 2565 2227 l 2565 2167 l 2413 2167 l 2413 2167 l 2533 2197 l 2413 2227 l cp 209 | eoclip 210 | n 2175 2197 m 211 | 2550 2197 l gs col0 s gr gr 212 | 213 | % arrowhead 214 | n 2413 2227 m 2533 2197 l 2413 2167 l col0 s 215 | % Polyline 216 | gs clippath 217 | 2413 2752 m 2565 2752 l 2565 2692 l 2413 2692 l 2413 2692 l 2533 2722 l 2413 2752 l cp 218 | eoclip 219 | n 2175 2722 m 220 | 2550 2722 l gs col0 s gr gr 221 | 222 | % arrowhead 223 | n 2413 2752 m 2533 2722 l 2413 2692 l col0 s 224 | % Polyline 225 | gs clippath 226 | 5263 2227 m 5415 2227 l 5415 2167 l 5263 2167 l 5263 2167 l 5383 2197 l 5263 2227 l cp 227 | eoclip 228 | n 5025 2197 m 229 | 5400 2197 l gs col0 s gr gr 230 | 231 | % arrowhead 232 | n 5263 2227 m 5383 2197 l 5263 2167 l col0 s 233 | % Polyline 234 | gs clippath 235 | 5263 1702 m 5415 1702 l 5415 1642 l 5263 1642 l 5263 1642 l 5383 1672 l 5263 1702 l cp 236 | eoclip 237 | n 5025 1672 m 238 | 5400 1672 l gs col0 s gr gr 239 | 240 | % arrowhead 241 | n 5263 1702 m 5383 1672 l 5263 1642 l col0 s 242 | % Polyline 243 | gs clippath 244 | 5263 1177 m 5415 1177 l 5415 1117 l 5263 1117 l 5263 1117 l 5383 1147 l 5263 1177 l cp 245 | eoclip 246 | n 5025 1147 m 247 | 5400 1147 l gs col0 s gr gr 248 | 249 | % arrowhead 250 | n 5263 1177 m 5383 1147 l 5263 1117 l col0 s 251 | /Helvetica ff 183.33 scf sf 252 | 2100 1200 m 253 | gs 1 -1 sc (n) dup sw pop neg 0 rm col0 sh gr 254 | /Helvetica ff 183.33 scf sf 255 | 2625 1200 m 256 | gs 1 -1 sc (3) col0 sh gr 257 | /Helvetica ff 183.33 scf sf 258 | 3600 1200 m 259 | gs 1 -1 sc (recurse) dup sw pop neg 0 rm col0 sh gr 260 | /Helvetica ff 183.33 scf sf 261 | 4125 1200 m 262 | gs 1 -1 sc (2) col0 sh gr 263 | /Helvetica ff 183.33 scf sf 264 | 3600 1725 m 265 | gs 1 -1 sc (recurse) dup sw pop neg 0 rm col0 sh gr 266 | /Helvetica ff 183.33 scf sf 267 | 4125 1725 m 268 | gs 1 -1 sc (1) col0 sh gr 269 | /Helvetica ff 183.33 scf sf 270 | 3600 2250 m 271 | gs 1 -1 sc (recurse) dup sw pop neg 0 rm col0 sh gr 272 | /Helvetica ff 183.33 scf sf 273 | 4125 2250 m 274 | gs 1 -1 sc (1) col0 sh gr 275 | /Helvetica ff 183.33 scf sf 276 | 1650 675 m 277 | gs 1 -1 sc (__main__) dup sw pop neg 0 rm col0 sh gr 278 | /Helvetica ff 183.33 scf sf 279 | 1650 1200 m 280 | gs 1 -1 sc (factorial) dup sw pop neg 0 rm col0 sh gr 281 | /Helvetica ff 183.33 scf sf 282 | 2100 1725 m 283 | gs 1 -1 sc (n) dup sw pop neg 0 rm col0 sh gr 284 | /Helvetica ff 183.33 scf sf 285 | 2625 1725 m 286 | gs 1 -1 sc (2) col0 sh gr 287 | /Helvetica ff 183.33 scf sf 288 | 2100 2250 m 289 | gs 1 -1 sc (n) dup sw pop neg 0 rm col0 sh gr 290 | /Helvetica ff 183.33 scf sf 291 | 2625 2250 m 292 | gs 1 -1 sc (1) col0 sh gr 293 | /Helvetica ff 183.33 scf sf 294 | 2100 2775 m 295 | gs 1 -1 sc (n) dup sw pop neg 0 rm col0 sh gr 296 | /Helvetica ff 183.33 scf sf 297 | 2625 2775 m 298 | gs 1 -1 sc (0) col0 sh gr 299 | /Helvetica ff 183.33 scf sf 300 | 1650 1725 m 301 | gs 1 -1 sc (factorial) dup sw pop neg 0 rm col0 sh gr 302 | /Helvetica ff 183.33 scf sf 303 | 1650 2250 m 304 | gs 1 -1 sc (factorial) dup sw pop neg 0 rm col0 sh gr 305 | /Helvetica ff 183.33 scf sf 306 | 1650 2775 m 307 | gs 1 -1 sc (factorial) dup sw pop neg 0 rm col0 sh gr 308 | /Helvetica ff 183.33 scf sf 309 | 6000 2550 m 310 | gs 1 -1 sc (1) col0 sh gr 311 | /Helvetica ff 183.33 scf sf 312 | 6000 2025 m 313 | gs 1 -1 sc (1) col0 sh gr 314 | /Helvetica ff 183.33 scf sf 315 | 6000 1500 m 316 | gs 1 -1 sc (2) col0 sh gr 317 | /Helvetica ff 183.33 scf sf 318 | 6000 975 m 319 | gs 1 -1 sc (6) col0 sh gr 320 | /Helvetica ff 183.33 scf sf 321 | 5475 2250 m 322 | gs 1 -1 sc (1) col0 sh gr 323 | /Helvetica ff 183.33 scf sf 324 | 4950 2250 m 325 | gs 1 -1 sc (result) dup sw pop neg 0 rm col0 sh gr 326 | /Helvetica ff 183.33 scf sf 327 | 5475 1725 m 328 | gs 1 -1 sc (2) col0 sh gr 329 | /Helvetica ff 183.33 scf sf 330 | 5475 1200 m 331 | gs 1 -1 sc (6) col0 sh gr 332 | /Helvetica ff 183.33 scf sf 333 | 4950 1200 m 334 | gs 1 -1 sc (result) dup sw pop neg 0 rm col0 sh gr 335 | /Helvetica ff 183.33 scf sf 336 | 4950 1725 m 337 | gs 1 -1 sc (result) dup sw pop neg 0 rm col0 sh gr 338 | % here ends figure; 339 | pagefooter 340 | showpage 341 | %%Trailer 342 | %EOF 343 | -------------------------------------------------------------------------------- /book/figs/stack3.fig: -------------------------------------------------------------------------------- 1 | #FIG 3.2 Produced by xfig version 3.2.5c 2 | Landscape 3 | Center 4 | Inches 5 | Letter 6 | 100.00 7 | Single 8 | -2 9 | 1200 2 10 | 5 1 0 1 0 7 50 0 -1 0.000 0 1 1 0 5700.000 2475.000 5700 2700 5925 2475 5700 2250 11 | 0 0 1.00 60.00 120.00 12 | 5 1 0 1 0 7 50 0 -1 0.000 0 1 1 0 5700.000 1950.000 5700 2175 5925 1950 5700 1725 13 | 0 0 1.00 60.00 120.00 14 | 5 1 0 1 0 7 50 0 -1 0.000 0 1 1 0 5700.000 900.000 5700 1125 5925 900 5700 675 15 | 0 0 1.00 60.00 120.00 16 | 5 1 0 1 0 7 50 0 -1 0.000 0 1 1 0 5700.000 1425.000 5700 1650 5925 1425 5700 1200 17 | 0 0 1.00 60.00 120.00 18 | 6 1950 1050 2775 1200 19 | 2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2 20 | 0 0 1.00 60.00 120.00 21 | 2175 1147 2550 1147 22 | 4 2 0 50 0 16 11 0.0000 4 90 90 2100 1200 n\001 23 | 4 0 0 50 0 16 11 0.0000 4 135 90 2625 1200 3\001 24 | -6 25 | 6 3075 1050 4275 2250 26 | 6 3075 1050 4275 1200 27 | 2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2 28 | 0 0 1.00 60.00 120.00 29 | 3675 1147 4050 1147 30 | 4 2 0 50 0 16 11 0.0000 4 90 630 3600 1200 recurse\001 31 | 4 0 0 50 0 16 11 0.0000 4 135 90 4125 1200 2\001 32 | -6 33 | 6 3075 1575 4275 1725 34 | 2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2 35 | 0 0 1.00 60.00 120.00 36 | 3675 1672 4050 1672 37 | 4 2 0 50 0 16 11 0.0000 4 90 630 3600 1725 recurse\001 38 | 4 0 0 50 0 16 11 0.0000 4 135 90 4125 1725 1\001 39 | -6 40 | 6 3075 2100 4275 2250 41 | 2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2 42 | 0 0 1.00 60.00 120.00 43 | 3675 2197 4050 2197 44 | 4 2 0 50 0 16 11 0.0000 4 90 630 3600 2250 recurse\001 45 | 4 0 0 50 0 16 11 0.0000 4 135 90 4125 2250 1\001 46 | -6 47 | -6 48 | 2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2 49 | 0 0 1.00 60.00 120.00 50 | 2175 1672 2550 1672 51 | 2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2 52 | 0 0 1.00 60.00 120.00 53 | 2175 2197 2550 2197 54 | 2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2 55 | 0 0 1.00 60.00 120.00 56 | 2175 2722 2550 2722 57 | 2 2 0 1 0 7 51 0 18 0.000 0 0 -1 0 0 5 58 | 1800 975 5700 975 5700 1350 1800 1350 1800 975 59 | 2 2 0 1 0 7 51 0 18 0.000 0 0 -1 0 0 5 60 | 1800 1500 5700 1500 5700 1875 1800 1875 1800 1500 61 | 2 2 0 1 0 7 51 0 18 0.000 0 0 -1 0 0 5 62 | 1800 2025 5700 2025 5700 2400 1800 2400 1800 2025 63 | 2 2 0 1 0 7 51 0 18 0.000 0 0 -1 0 0 5 64 | 1800 2550 5700 2550 5700 2925 1800 2925 1800 2550 65 | 2 2 0 1 0 7 51 0 18 0.000 0 0 -1 0 0 5 66 | 1800 450 5700 450 5700 825 1800 825 1800 450 67 | 2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2 68 | 0 0 1.00 60.00 120.00 69 | 5025 2197 5400 2197 70 | 2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2 71 | 0 0 1.00 60.00 120.00 72 | 5025 1672 5400 1672 73 | 2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2 74 | 0 0 1.00 60.00 120.00 75 | 5025 1147 5400 1147 76 | 4 2 0 50 0 16 11 0.0000 4 135 720 1650 675 __main__\001 77 | 4 2 0 50 0 16 11 0.0000 4 135 810 1650 1200 factorial\001 78 | 4 2 0 50 0 16 11 0.0000 4 90 90 2100 1725 n\001 79 | 4 0 0 50 0 16 11 0.0000 4 135 90 2625 1725 2\001 80 | 4 2 0 50 0 16 11 0.0000 4 90 90 2100 2250 n\001 81 | 4 0 0 50 0 16 11 0.0000 4 135 90 2625 2250 1\001 82 | 4 2 0 50 0 16 11 0.0000 4 90 90 2100 2775 n\001 83 | 4 0 0 50 0 16 11 0.0000 4 135 90 2625 2775 0\001 84 | 4 2 0 50 0 16 11 0.0000 4 135 810 1650 1725 factorial\001 85 | 4 2 0 50 0 16 11 0.0000 4 135 810 1650 2250 factorial\001 86 | 4 2 0 50 0 16 11 0.0000 4 135 810 1650 2775 factorial\001 87 | 4 0 0 50 0 16 11 0.0000 4 135 90 6000 2550 1\001 88 | 4 0 0 50 0 16 11 0.0000 4 135 90 6000 2025 1\001 89 | 4 0 0 50 0 16 11 0.0000 4 135 90 6000 1500 2\001 90 | 4 0 0 50 0 16 11 0.0000 4 135 90 6000 975 6\001 91 | 4 0 0 50 0 16 11 0.0000 4 135 90 5475 2250 1\001 92 | 4 2 0 50 0 16 11 0.0000 4 135 540 4950 2250 result\001 93 | 4 0 0 50 0 16 11 0.0000 4 135 90 5475 1725 2\001 94 | 4 0 0 50 0 16 11 0.0000 4 135 90 5475 1200 6\001 95 | 4 2 0 50 0 16 11 0.0000 4 135 540 4950 1200 result\001 96 | 4 2 0 50 0 16 11 0.0000 4 135 540 4950 1725 result\001 97 | -------------------------------------------------------------------------------- /book/figs/stack3.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LaurentRosenfeld/thinkperl6/8223c17d3437475e4e9602699b9348ee53c24c04/book/figs/stack3.pdf -------------------------------------------------------------------------------- /book/figs/stack_diagram.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LaurentRosenfeld/thinkperl6/8223c17d3437475e4e9602699b9348ee53c24c04/book/figs/stack_diagram.pdf -------------------------------------------------------------------------------- /book/figs/stack_diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LaurentRosenfeld/thinkperl6/8223c17d3437475e4e9602699b9348ee53c24c04/book/figs/stack_diagram.png -------------------------------------------------------------------------------- /book/figs/state6.pfi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LaurentRosenfeld/thinkperl6/8223c17d3437475e4e9602699b9348ee53c24c04/book/figs/state6.pfi -------------------------------------------------------------------------------- /book/figs/state6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LaurentRosenfeld/thinkperl6/8223c17d3437475e4e9602699b9348ee53c24c04/book/figs/state6.png -------------------------------------------------------------------------------- /book/figs/test_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LaurentRosenfeld/thinkperl6/8223c17d3437475e4e9602699b9348ee53c24c04/book/figs/test_2.png -------------------------------------------------------------------------------- /book/figs/test_5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LaurentRosenfeld/thinkperl6/8223c17d3437475e4e9602699b9348ee53c24c04/book/figs/test_5.png -------------------------------------------------------------------------------- /book/footer.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |

6 |

Are you using one of our books in a class?

We'd like to know 7 | about it. Please consider filling out this short survey. 8 | 9 |

10 |
11 | 12 |

13 | Think DSP 14 | 15 | 16 |

17 | 18 | 19 | 20 | 21 |

22 | Think Java 23 | 24 | 25 |

26 | 27 | 28 | 29 | 30 |

31 | Think Bayes 32 | 33 | 34 |

35 | 36 | 37 | 38 | 39 |

40 | Think Python 2e 41 | 42 | 43 |

44 | 45 | 46 | 47 | 48 |

49 | Think Stats 2e 50 | 51 | 52 |

53 | 54 | 55 | 56 | 57 |

58 | Think Complexity 59 | 60 | 61 |

62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /book/header.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | 8 |
6 | 9 | 10 |

This HTML version of Think Perl 6 is provided for convenience, but it is not the best format of the book. You might prefer to read the PDF version. 11 | 12 | -------------------------------------------------------------------------------- /book/hevea.sty: -------------------------------------------------------------------------------- 1 | % hevea : hevea.sty 2 | % This is a very basic style file for latex document to be processed 3 | % with hevea. It contains definitions of LaTeX environment which are 4 | % processed in a special way by the translator. 5 | % Mostly : 6 | % - latexonly, not processed by hevea, processed by latex. 7 | % - htmlonly , the reverse. 8 | % - rawhtml, to include raw HTML in hevea output. 9 | % - toimage, to send text to the image file. 10 | % The package also provides hevea logos, html related commands (ahref 11 | % etc.), void cutting and image commands. 12 | \NeedsTeXFormat{LaTeX2e} 13 | \ProvidesPackage{hevea}[2002/01/11] 14 | \RequirePackage{comment} 15 | \newif\ifhevea\heveafalse 16 | \@ifundefined{ifimagen}{\newif\ifimagen\imagenfalse} 17 | \makeatletter% 18 | \newcommand{\heveasmup}[2]{% 19 | \raise #1\hbox{$\m@th$% 20 | \csname S@\f@size\endcsname 21 | \fontsize\sf@size 0% 22 | \math@fontsfalse\selectfont 23 | #2% 24 | }}% 25 | \DeclareRobustCommand{\hevea}{H\kern-.15em\heveasmup{.2ex}{E}\kern-.15emV\kern-.15em\heveasmup{.2ex}{E}\kern-.15emA}% 26 | \DeclareRobustCommand{\hacha}{H\kern-.15em\heveasmup{.2ex}{A}\kern-.15emC\kern-.1em\heveasmup{.2ex}{H}\kern-.15emA}% 27 | \DeclareRobustCommand{\html}{\protect\heveasmup{0.ex}{HTML}} 28 | %%%%%%%%% Hyperlinks hevea style 29 | \newcommand{\ahref}[2]{{#2}} 30 | \newcommand{\ahrefloc}[2]{{#2}} 31 | \newcommand{\aname}[2]{{#2}} 32 | \newcommand{\ahrefurl}[1]{\texttt{#1}} 33 | \newcommand{\footahref}[2]{#2\footnote{\texttt{#1}}} 34 | \newcommand{\mailto}[1]{\texttt{#1}} 35 | \newcommand{\imgsrc}[2][]{} 36 | \newcommand{\home}[1]{\protect\raisebox{-.75ex}{\char126}#1} 37 | \AtBeginDocument 38 | {\@ifundefined{url} 39 | {%url package is not loaded 40 | \let\url\ahref\let\oneurl\ahrefurl\let\footurl\footahref} 41 | {}} 42 | %% Void cutting instructions 43 | \newcounter{cuttingdepth} 44 | \newcommand{\tocnumber}{} 45 | \newcommand{\notocnumber}{} 46 | \newcommand{\cuttingunit}{} 47 | \newcommand{\cutdef}[2][]{} 48 | \newcommand{\cuthere}[2]{} 49 | \newcommand{\cutend}{} 50 | \newcommand{\htmlhead}[1]{} 51 | \newcommand{\htmlfoot}[1]{} 52 | \newcommand{\htmlprefix}[1]{} 53 | \newenvironment{cutflow}[1]{}{} 54 | \newcommand{\cutname}[1]{} 55 | \newcommand{\toplinks}[3]{} 56 | \newcommand{\setlinkstext}[3]{} 57 | \newcommand{\flushdef}[1]{} 58 | \newcommand{\footnoteflush}[1]{} 59 | %%%% Html only 60 | \excludecomment{rawhtml} 61 | \newcommand{\rawhtmlinput}[1]{} 62 | \excludecomment{htmlonly} 63 | %%%% Latex only 64 | \newenvironment{latexonly}{}{} 65 | \newenvironment{verblatex}{}{} 66 | %%%% Image file stuff 67 | \def\toimage{\endgroup} 68 | \def\endtoimage{\begingroup\def\@currenvir{toimage}} 69 | \def\verbimage{\endgroup} 70 | \def\endverbimage{\begingroup\def\@currenvir{verbimage}} 71 | \newcommand{\imageflush}[1][]{} 72 | %%% Bgcolor definition 73 | \newsavebox{\@bgcolorbin} 74 | \newenvironment{bgcolor}[2][] 75 | {\newcommand{\@mycolor}{#2}\begin{lrbox}{\@bgcolorbin}\vbox\bgroup} 76 | {\egroup\end{lrbox}% 77 | \begin{flushleft}% 78 | \colorbox{\@mycolor}{\usebox{\@bgcolorbin}}% 79 | \end{flushleft}} 80 | %%% Style sheets macros, defined as no-ops 81 | \newcommand{\newstyle}[2]{} 82 | \newcommand{\addstyle}[1]{} 83 | \newcommand{\setenvclass}[2]{} 84 | \newcommand{\getenvclass}[1]{} 85 | \newcommand{\loadcssfile}[1]{} 86 | \newenvironment{divstyle}[1]{}{} 87 | \newenvironment{cellstyle}[2]{}{} 88 | \newif\ifexternalcss 89 | %%% Postlude 90 | \makeatother 91 | -------------------------------------------------------------------------------- /book/intro_part_1.tex: -------------------------------------------------------------------------------- 1 | % intro_part_1.tex -- Introduction to first part of the book 2 | % 3 | 4 | This book has been divided in two parts. The main reason for that 5 | is that I wanted to make a distinction between on the one hand 6 | relatively basic notions that are really needed for any programmer 7 | using Perl 6, and on the other hand more advanced concepts that 8 | a good programmer needs to know but may be less often needed in 9 | the day-to-day development work. 10 | 11 | The first eleven chapters (a bit more than 200~pages) which make up 12 | this first part are meant to teach the concepts that every 13 | programmer should know: variables, expressions, statements, 14 | functions, conditionals, recursion, operator precedence, loops, etc., 15 | as well as the basic data structures commonly used, and the most 16 | useful algorithms. These chapters can, I believe, be the basis 17 | for a one-semester introductory course on programming. 18 | 19 | Of course, the professor or teacher that wishes to use this 20 | material is entirely free to skip some details from this 21 | Part~1 (and also to include sections from Part~2), but, at 22 | least, I have provided some guidelines on how I think this 23 | book could be used to teach programming using the Perl~6 language. 24 | 25 | The second part focuses on different programming paradigms and 26 | more advanced programming techniques that are in my opinion of 27 | paramount importance, but should probably be studied in the context 28 | of a second, more advanced, semester. 29 | 30 | For now, let's get down to the basics. It is my hope that you 31 | will enjoy the trip. 32 | 33 | -------------------------------------------------------------------------------- /book/intro_part_2.tex: -------------------------------------------------------------------------------- 1 | % intro_part_2.tex -- Introduction to second part 2 | % 3 | % \chapter{Introduction to the Second part of this book} 4 | 5 | Now that you have reached the end of the first part 6 | of this book, you should non longer be a pure beginner. 7 | By now, you should be able to go through the official 8 | Perl~6 documentation (\url{https://docs.perl6.org}) 9 | and find your way. 10 | 11 | There are many more things to say about programming. 12 | The next three chapters will be devoted to more 13 | advanced concepts and new programming paradigms, including: 14 | \begin{description} 15 | 16 | \item[Object-oriented programming] We will describe how 17 | we can construct our own types and methods, which 18 | is a way to extend the language. 19 | 20 | \item[Using grammars] This is a form of declarative 21 | programming in which you define axioms and rules 22 | and derive knowledge from these; grammars are a 23 | very powerful way to analyze textual content and 24 | are used to transform program source code into 25 | executable statements. 26 | 27 | \item[Functional programming] This is yet another programming 28 | paradigm in which computation is expressed as the 29 | evaluation of mathematical functions. 30 | \end{description} 31 | 32 | Each of these chapters probably deserves a full 33 | book in its own right (and might have one some day), 34 | but we hope to tell you enough about them to get you 35 | going. In my opinion, every programmer should know 36 | about these powerful concepts in order to be able 37 | to select the best way to solve a given problem. 38 | 39 | Perl~6 is a multiparadigm language, so we can 40 | really cover these topics in terms of the Perl~6 41 | language. A number of subjects that we have 42 | introduced in previous chapters should lead you 43 | easily into these new ideas, and this is the 44 | reason why I think it is possible to properly cover 45 | them with just one chapter for each of these subjects. 46 | 47 | There will be far fewer exercises in the second part, 48 | because we expect you by now to be able to think up 49 | your own exercises and make your own experiments for 50 | yourself. And there will be only very few suggested solutions, 51 | because we are getting at a level where there is really not 52 | one right solution, but many possible ways to tackle 53 | a problem. 54 | 55 | Concerning the Perl language, we have covered a lot of 56 | material, but, as I warned from the very beginning, 57 | this is far from exhaustive. The following are among 58 | the topics that we have not covered (and will not cover); 59 | you might want to explore the documentation on them 60 | yourself: 61 | 62 | \begin{description} 63 | \item[Concurrent programming] Today's computers have 64 | multiple processors or multicore processors; Perl~6 65 | offers various ways of taking advantage of these to 66 | run computing processes in parallel in order to 67 | improve performance and reduce run time; see 68 | \url{https://docs.perl6.org/language/concurrency} 69 | for more details. 70 | 71 | \item[Exception handling] Managing situations where 72 | something goes wrong is an important part of 73 | programming. Perl~6 offers various mechanisms to 74 | handle such situations. See \url{https://docs.perl6.org/language/exceptions} 75 | for more details. 76 | 77 | \item[Interprocess communication:] Programs often have to 78 | run other programs and to communicate with them. See 79 | \url{https://docs.perl6.org/language/ipc}. 80 | 81 | \item[Modules] How to create, use, and distribute Perl~6 82 | modules. See \url{https://docs.perl6.org/language/modules}. 83 | 84 | \item[Native calling interface] How to call libraries 85 | that are written in other programming languages and 86 | follow the C calling conventions. 87 | See \url{https://docs.perl6.org/language/nativecall} 88 | 89 | \end{description} -------------------------------------------------------------------------------- /book/latexonly.sty: -------------------------------------------------------------------------------- 1 | % This file contains global declarations that latex2html doesn't want to 2 | % see. The latexonly environment doesn't work here because they need 3 | % to have global scope. latex2html ignores this style option completely 4 | % as long as ``latexonly'' is listed in the $DONT_INCLUDE variable 5 | % in the .latex2html-init file. 6 | 7 | \sansfont{helvetica} 8 | \typewriterfont{cmtt} 9 | 10 | \newcommand{\bold}{\fontfamily{cmr}\series{bx}\shape{n}\size{12}{12pt}% 11 | \selectfont} 12 | \newcommand{\smallfont}{\fontfamily{cmr}\series{m}\shape{n}\size{10}{11pt}% 13 | \selectfont} 14 | \newcommand{\sem}{\fontfamily{cmr}\series{m}\shape{sl}\size{10}{11pt}% 15 | \selectfont} 16 | 17 | \def\caps{\family{palatino}\size{12}{12pt}\selectfont} 18 | \def\nintt{\family{helvetica}\size{9}{11pt}\selectfont} 19 | \def\sanss{\family{helvetica}\size{11}{11pt}\selectfont} 20 | \def\smalltt{\family{courier}\size{9}{11pt}\selectfont} 21 | 22 | % 23 | % bigverb is used to typeset verbatim text that is wide and needs to 24 | % be typeset in a smaller font. latex2html doesn't like the 25 | % \verbatim command and has bigverb support hardcoded into it already, 26 | % that's why it is here in latexonly.sty. 27 | % 28 | \newenvironment{bigverb}{\small\verbatim}{\endverbatim} 29 | 30 | \makeatletter 31 | \newcommand{\protspec}[2]{\addcontentsline{toc}{subsection}{#1}% 32 | \subsection*{NAME} #2} 33 | \newcommand{\topic}[1]{\subsection*{#1}} 34 | \makeatother 35 | -------------------------------------------------------------------------------- /book/latexonly.tex: -------------------------------------------------------------------------------- 1 | \sloppy 2 | %\setlength{\topmargin}{-0.375in} 3 | %\setlength{\oddsidemargin}{0.0in} 4 | %\setlength{\evensidemargin}{0.0in} 5 | 6 | % Uncomment these to center on 8.5 x 11 7 | %\setlength{\topmargin}{0.625in} 8 | %\setlength{\oddsidemargin}{0.875in} 9 | %\setlength{\evensidemargin}{0.875in} 10 | 11 | %\setlength{\textheight}{7.2in} 12 | 13 | \setlength{\headsep}{3ex} 14 | \setlength{\parindent}{0.0in} 15 | \setlength{\parskip}{1.7ex plus 0.5ex minus 0.5ex} 16 | \renewcommand{\baselinestretch}{1.02} 17 | 18 | % see LaTeX Companion page 62 19 | \setlength{\topsep}{-0.0\parskip} 20 | \setlength{\partopsep}{-0.5\parskip} 21 | \setlength{\itemindent}{0.0in} 22 | \setlength{\listparindent}{0.0in} 23 | 24 | % see LaTeX Companion page 26 25 | % these are copied from /usr/local/teTeX/share/texmf/tex/latex/base/book.cls 26 | % all I changed is afterskip 27 | 28 | \makeatletter 29 | 30 | \renewcommand{\section}{\@startsection 31 | {section} {1} {0mm}% 32 | {-3.5ex \@plus -1ex \@minus -.2ex}% 33 | {0.7ex \@plus.2ex}% 34 | {\normalfont\Large\bfseries}} 35 | \renewcommand\subsection{\@startsection {subsection}{2}{0mm}% 36 | {-3.25ex\@plus -1ex \@minus -.2ex}% 37 | {0.3ex \@plus .2ex}% 38 | {\normalfont\large\bfseries}} 39 | \renewcommand\subsubsection{\@startsection {subsubsection}{3}{0mm}% 40 | {-3.25ex\@plus -1ex \@minus -.2ex}% 41 | {0.3ex \@plus .2ex}% 42 | {\normalfont\normalsize\bfseries}} 43 | 44 | % The following line adds a little extra space to the column 45 | % in which the Section numbers appear in the table of contents 46 | \renewcommand{\l@section}{\@dottedtocline{1}{1.5em}{3.0em}} 47 | \setcounter{tocdepth}{2} 48 | 49 | \makeatother 50 | 51 | \newcommand{\beforefig}{\vspace{1.3\parskip}} 52 | \newcommand{\afterfig}{\vspace{-0.2\parskip}} 53 | 54 | \newcommand{\beforeverb}{\vspace{0.6\parskip}} 55 | \newcommand{\afterverb}{\vspace{0.6\parskip}} 56 | 57 | \newcommand{\adjustpage}[1]{\enlargethispage{#1\baselineskip}} 58 | 59 | 60 | % Note: the following command seems to cause problems for Acroreader 61 | % on Windows, so for now I am overriding it. 62 | %\newcommand{\clearemptydoublepage}{ 63 | % \newpage{\pagestyle{empty}\cleardoublepage}} 64 | \newcommand{\clearemptydoublepage}{\cleardoublepage} 65 | 66 | %\newcommand{\blankpage}{\pagestyle{empty}\vspace*{1in}\newpage} 67 | \newcommand{\blankpage}{\vspace*{1in}\newpage} 68 | 69 | % HEADERS 70 | 71 | \renewcommand{\chaptermark}[1]{\markboth{#1}{}} 72 | \renewcommand{\sectionmark}[1]{\markright{\thesection\ #1}{}} 73 | 74 | \lhead[\fancyplain{}{\bfseries\thepage}]% 75 | {\fancyplain{}{\bfseries\rightmark}} 76 | \rhead[\fancyplain{}{\bfseries\leftmark}]% 77 | {\fancyplain{}{\bfseries\thepage}} 78 | \cfoot{} 79 | 80 | \pagestyle{fancyplain} 81 | 82 | 83 | % turn off the rule under the header 84 | %\setlength{\headrulewidth}{0pt} 85 | 86 | % the following is a brute-force way to prevent the headers 87 | % from getting transformed into all-caps 88 | \renewcommand\MakeUppercase{} 89 | 90 | % Exercise environment 91 | \newtheoremstyle{myex}% name 92 | {9pt}% Space above 93 | {9pt}% Space below 94 | {}% Body font 95 | {}% Indent amount (empty = no indent, \parindent = para indent) 96 | {\bfseries}% Thm head font 97 | {}% Punctuation after thm head 98 | {0.5em}% Space after thm head: " " = normal interword space; 99 | % \newline = linebreak 100 | {}% Thm head spec (can be left empty, meaning `normal') 101 | 102 | \theoremstyle{myex} 103 | -------------------------------------------------------------------------------- /book/next.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LaurentRosenfeld/thinkperl6/8223c17d3437475e4e9602699b9348ee53c24c04/book/next.png -------------------------------------------------------------------------------- /book/preface.tex: -------------------------------------------------------------------------------- 1 | 2 | \chapter{Preface} 3 | 4 | Welcome to the art of computer programming and to the 5 | new Perl~6 language. This will probably be 6 | the first published book using Perl~6 (or one of the first), 7 | a powerful, expressive, malleable and highly extensible 8 | programming language. But this book is less 9 | about Perl~6, and more about learning 10 | how to write programs for computers. 11 | 12 | This book is intended for beginners and does not require 13 | any prior programming knowledge, but it is my hope 14 | that even those of you with programming experience will 15 | benefit from reading it. 16 | 17 | \section*{The Aim of this Book} 18 | 19 | This aim of this book is not primarily to teach Perl~6, 20 | but instead to teach the art 21 | of programming, using the Perl~6 language. After having 22 | completed this book, you should hopefully be able 23 | to write programs to solve relatively difficult problems in 24 | Perl~6, but my main aim is to teach computer science, software 25 | programming, and problem solving rather than solely to teach 26 | the Perl~6 language itself. 27 | 28 | This means that I will not cover every aspect of Perl~6, but 29 | only a (relatively large, but yet incomplete) subset of it. 30 | By no means is this book intended to be a reference on the 31 | language. 32 | 33 | It is not possible to learn programming or to learn a new 34 | programming language by just reading a book; practicing 35 | is essential. This book contains a lot of exercises. You 36 | are strongly encouraged to make a real effort to do them. And, 37 | whether successful or not in solving the exercises, you 38 | should take a look at the solutions in the Appendix, 39 | as, very often, several solutions are suggested with further 40 | discussion on the subject and the issues involved. Sometimes, the solution 41 | section of the Appendix also introduces examples of topics 42 | that will be covered in the next chapter--and sometimes even 43 | things that are not covered elsewhere in the book. So, to get 44 | the most out the book, I suggest you try to solve the exercises 45 | as well as review the solutions and attempt them. 46 | 47 | There are more than one thousand code examples in this book; 48 | study them, make sure to understand them, and run them. When 49 | possible, try to change them and see what happens. You're 50 | likely to learn a lot from this process. 51 | 52 | 53 | \section*{The History of this Book} 54 | 55 | In the course of the last three to four years, I 56 | have translated or adapted to French a number of tutorials 57 | and articles on Perl 6, and I've also written a few entirely 58 | new ones in French.~\footnote{See for example 59 | \url{http://perl.developpez.com/cours/\#TutorielsPerl6}.} 60 | Together, these documents represented by the end of 2015 61 | somewhere between 250 and 300 pages of material on Perl~6. 62 | By that time, I had 63 | probably made public more material on Perl~6 in French than 64 | all other authors taken together. 65 | 66 | In late 2015, I began to feel that a Perl~6 document for beginners 67 | was something missing that I was willing to undertake. 68 | I looked around and found that it did not seem to 69 | exist in English either. I came to the idea that, after all, 70 | it might be more useful to write such a document initially 71 | in English, to give it a broader audience. I started contemplating 72 | writing a beginner introduction to Perl~6 73 | programming. My idea at the time was something like a 50- to 74 | 70-page tutorial and I started to gather material and ideas 75 | in this direction. 76 | 77 | Then, something happened that changed my plans. 78 | 79 | In December 2015, friends of mine were contemplating translating 80 | into French Allen B. Downey's \emph{Think Python, Second Edition}\footnote{See \url{http://greenteapress.com/wp/think-python-2e/}.}. 81 | I had read an earlier edition of that book and fully supported 82 | the idea of translating it\footnote{I know, it's 83 | about Python, not Perl. But I don't believe in engaging 84 | in ``language wars'' and think that we all have to learn from 85 | other languages; to me, Perl's motto, ``there is more than 86 | one way to do it,'' also means that doing it in Python (or some 87 | other language) is truly an acceptable possibility.}. As it 88 | turned out, I ended up being a co-translator and the technical 89 | editor of the French translation of that book\footnote{See 90 | \url{http://allen-downey.developpez.com/livres/python/pensez-python/}.}. 91 | 92 | While working on the French translation of Allen's Python book, 93 | the idea came to me that, rather than writing a tutorial on 94 | Perl~6, it might be more useful to make a ``Perl~6 translation'' 95 | of \emph{Think Python}. Since I was in contact with Allen in the context 96 | of the French translation, I suggested this to Allen, who 97 | warmly welcomed the idea. This is how I started to write this 98 | book late January 2016, just after having completed the 99 | work on the French translation of his Python book. 100 | 101 | This book is thus largely derived on Allen's \emph{Think Python}, 102 | but adapted to Perl~6. As it happened, it is also much more 103 | than just a ``Perl~6 translation'' of Allen's book: with 104 | quite a lot of new material, it has become a brand new book, 105 | largely indebted to Allen's book, but yet a new book for which 106 | I take all responsibility. Any errors are mine, 107 | not Allen's. 108 | 109 | My hope is that this will be useful to the Perl~6 community, and 110 | more broadly to the open source and general 111 | computer programming communities. In an interview with 112 | \emph{LinuxVoice} (July 2015), Larry Wall, the creator of Perl~6, 113 | said: ``We do think that Perl 6 will be learnable as a first language.'' 114 | Hopefully this book will contribute to making this happen. 115 | 116 | \section*{Acknowledgments} 117 | 118 | I just don't know how I could thank Larry Wall to the level of 119 | gratitude that he deserves for having created Perl in the first 120 | place, and Perl~6 more recently. Be blessed for eternity, Larry, 121 | for all of that. 122 | 123 | And thank to you all of you who took part to this 124 | adventure (in no particular order), Tom, Damian, 125 | chromatic, Nathan, brian, Jan, Jarkko, John, Johan, Randall, 126 | Mark Jason, Ovid, Nick, Tim, Andy, Chip, Matt, Michael, Tatsuhiko, 127 | Dave, Rafael, Chris, Stevan, Saraty, Malcolm, Graham, Leon, 128 | Ricardo, Gurusamy, Scott and too many others to name. 129 | 130 | All my thanks also to those who believed in 131 | this Perl~6 project and made it happen, including those who 132 | quit at one point or another but contributed for some 133 | time; I know that this wasn't always easy. 134 | 135 | Many thanks to Allen Downey, who very kindly supported my idea of 136 | adapting his book to Perl~6 and helped me in many respects, but 137 | also refrained from interfering in what I was putting into 138 | this new book. 139 | 140 | I very warmly thank the people at O'Reilly who accepted the 141 | idea of this book and suggested many corrections or 142 | improvements. I want to thank especially 143 | Dawn Schanafelt, my editor at O'Reilly, whose advice 144 | has truly contributed to making this a better book. Many 145 | thanks also to Charles Roumeliotis, the copy editor, and 146 | Kristen Brown, the production editor, who fixed many 147 | typographical problems and spelling mistakes. 148 | 149 | Thanks a lot in advance to readers who will offer comments 150 | or submit suggestions or corrections, as well as encouragements. 151 | 152 | If you see anything that needs to be corrected or that 153 | could be improved, please kindly send your comments to 154 | \url{think.perl6 (at) gmail.com}. 155 | % ... 156 | 157 | 158 | \section*{Contributor List} 159 | 160 | % ... 161 | I would like to thank especially Moritz Lenz and Elizabeth 162 | Mattijsen, who reviewed in detail drafts of this book 163 | and suggested quite a number of improvements and corrections. Liz 164 | spent a lot of time on a detailed review of the full 165 | content of this book and I am especially grateful to her for 166 | her numerous and very useful comments. Thanks also to Timo Paulssen and 167 | ryanschoppe who also reviewed early drafts and provided some 168 | useful suggestions. Many thanks also to Uri Guttman, who reviewed 169 | this book and suggested a number of small corrections and improvements 170 | shortly before publication. 171 | 172 | Kamimura, James Lenz, and Jeff McClelland each submitted a couple 173 | of corrections in the errata list on the O'Reilly web site. 174 | zengargoyle pointed out a spurious character in a regex 175 | and fixed it in the GitHub repository of the book. zengargoyle 176 | also suggested a clarification in the chapter about functional 177 | programming. Another James (second name unknown to me) 178 | submitted an erratum on the O'Reilly web site. Mikhail Korenev 179 | suggested accurate corrections to three code samples. 180 | Sébastien Dorey, Jean Forget, and Roland Schmitz sent some e-mails 181 | suggesting a few useful corrections or improvements. 182 | Luis F. Uceta translated this book into Spanish and found in the 183 | process quite a few typos he corrected on the Github repository. 184 | Gil Magno, zoffixznet and Joaquin Ferrero also suggested some 185 | corrections on Github. Threadless-screw fixed a couple of 186 | faulty cross-references in the chapter about hashes. 187 | Boyd Duffee spotted two code samples that used to work fine when 188 | I wrote them four years ago, but no longer work, due to some 189 | implementation changes. leszekdubiel suggested an improvement 190 | that probably clarifies a bit the meaning of a sentence. 191 | 192 | \clearemptydoublepage 193 | 194 | % TABLE OF CONTENTS 195 | \begin{latexonly} 196 | 197 | \tableofcontents 198 | 199 | \clearemptydoublepage 200 | 201 | \end{latexonly} 202 | 203 | -------------------------------------------------------------------------------- /book/thinkperl6.tex: -------------------------------------------------------------------------------- 1 | % LaTeX source for ``Think Perl 6: How to Think Like a Computer Scientist'' 2 | 3 | % Copyright (c) 2017-2020 Allen B. Downey and Laurent Rosenfeld. 4 | 5 | % License: Creative Commons Attribution-NonCommercial 3.0 Unported License. 6 | % http://creativecommons.org/licenses/by-nc/3.0/ 7 | % 8 | 9 | %\documentclass[10pt,b5paper]{book} 10 | \documentclass[10pt]{book} 11 | \usepackage[width=5.5in,height=8.5in, 12 | hmarginratio=3:2,vmarginratio=1:1]{geometry} 13 | 14 | % for some of these packages, you might have to install 15 | % texlive-latex-extra (in Ubuntu) 16 | 17 | \usepackage[T1]{fontenc} 18 | \usepackage{textcomp} 19 | \usepackage{mathpazo} 20 | \usepackage{url} 21 | \usepackage{fancyhdr} 22 | \usepackage{graphicx} 23 | \usepackage{amsmath} 24 | \usepackage{amsthm} 25 | %\usepackage{amssymb} 26 | \usepackage{exercise} % texlive-latex-extra 27 | \usepackage{makeidx} 28 | %\usepackage{makeidx,showidx} 29 | \usepackage{setspace} 30 | \usepackage{hevea} 31 | \usepackage{upquote} 32 | \usepackage{appendix} 33 | \usepackage[bookmarks]{hyperref} 34 | \usepackage[english]{babel} 35 | \usepackage[mathletters]{ucs} 36 | \usepackage[utf8x]{inputenc} 37 | \usepackage{fancyvrb} 38 | %\usepackage{moreverb} 39 | 40 | \title{Think Perl 6} 41 | \author{Laurent Rosenfeld, with Allen B. Downey } 42 | \newcommand{\thetitle}{Think Perl 6: How to Think Like a Computer Scientist} 43 | \newcommand{\theversion}{1st Edition, Version 0.6.0} 44 | \newcommand{\thedate}{January 2020} 45 | 46 | % these styles get translated in CSS for the HTML version 47 | \newstyle{a:link}{color:black;} 48 | \newstyle{p+p}{margin-top:1em;margin-bottom:1em} 49 | \newstyle{img}{border:0px} 50 | 51 | % define verbatim environment with a left margin 52 | \DefineVerbatimEnvironment{verbatim}{Verbatim}{xleftmargin=.3in} 53 | 54 | % change the arrows 55 | \setlinkstext 56 | {\imgsrc[ALT="Previous"]{back.png}} 57 | {\imgsrc[ALT="Up"]{up.png}} 58 | {\imgsrc[ALT="Next"]{next.png}} 59 | 60 | \setcounter{secnumdepth}{3} 61 | 62 | \makeindex 63 | 64 | \newif\ifplastex 65 | \plastexfalse 66 | 67 | \begin{document} 68 | 69 | \frontmatter 70 | 71 | % PLASTEX ONLY 72 | \ifplastex 73 | \usepackage{localdef} 74 | \maketitle 75 | 76 | \newcount\anchorcnt 77 | \newcommand*{\Anchor}[1]{% 78 | \@bsphack% 79 | \Hy@GlobalStepCount\anchorcnt% 80 | \edef\@currentHref{anchor.\the\anchorcnt}% 81 | \Hy@raisedlink{\hyper@anchorstart{\@currentHref}\hyper@anchorend}% 82 | \M@gettitle{}\label{#1}% 83 | \@esphack% 84 | } 85 | 86 | 87 | \else 88 | % skip the following for plastex 89 | 90 | \newtheorem{exercise}{Exercise}[chapter] 91 | 92 | % LATEXONLY 93 | 94 | \input{latexonly} 95 | 96 | \begin{latexonly} 97 | 98 | \renewcommand{\blankpage}{\thispagestyle{empty} \quad \newpage} 99 | 100 | %\blankpage 101 | %\blankpage 102 | 103 | % TITLE PAGES FOR LATEX VERSION 104 | 105 | %-half title-------------------------------------------------- 106 | \thispagestyle{empty} 107 | 108 | \begin{flushright} 109 | \vspace*{2.0in} 110 | 111 | \begin{spacing}{3} 112 | {\huge Think Perl 6}\\ 113 | {\Large How to Think Like a Computer Scientist} 114 | \end{spacing} 115 | 116 | \vspace{0.25in} 117 | 118 | \theversion 119 | 120 | \thedate 121 | 122 | \vfill 123 | 124 | \end{flushright} 125 | 126 | %--verso------------------------------------------------------ 127 | 128 | \blankpage 129 | \blankpage 130 | %\clearemptydoublepage 131 | %\pagebreak 132 | %\thispagestyle{empty} 133 | %\vspace*{6in} 134 | 135 | %--title page-------------------------------------------------- 136 | \pagebreak 137 | \thispagestyle{empty} 138 | 139 | \begin{flushright} 140 | \vspace*{2.0in} 141 | 142 | \begin{spacing}{3} 143 | {\huge Think Perl 6}\\ 144 | {\Large How to Think Like a Computer Scientist} 145 | \end{spacing} 146 | 147 | \vspace{0.25in} 148 | 149 | \theversion 150 | 151 | \thedate 152 | 153 | \vspace{1in} 154 | 155 | 156 | {\Large 157 | Laurent Rosenfeld, 158 | with Allen B. Downey\\ 159 | } 160 | 161 | 162 | \vspace{0.5in} 163 | 164 | {\Large Green Tea Press} 165 | 166 | {\small Needham, Massachusetts} 167 | 168 | %\includegraphics[width=1in]{figs/logo1.pdf} 169 | \vfill 170 | 171 | \end{flushright} 172 | 173 | 174 | %--copyright-------------------------------------------------- 175 | \pagebreak 176 | \thispagestyle{empty} 177 | 178 | {\small 179 | Copyright \copyright ~2017 Allen Downey, Laurent Rosenfeld. 180 | 181 | 182 | \vspace{0.2in} 183 | 184 | \begin{flushleft} 185 | Green Tea Press \\ 186 | 9 Washburn Ave \\ 187 | Needham MA 02492 188 | \end{flushleft} 189 | 190 | Permission is granted to copy, distribute, and/or modify this document 191 | under the terms of the Creative Commons Attribution-NonCommercial 3.0 Unported 192 | License, which is available at \url{http://creativecommons.org/licenses/by-nc/3.0/}. 193 | 194 | The original form of this book is \LaTeX\ source code. Compiling this 195 | \LaTeX\ source has the effect of generating a device-independent 196 | representation of a textbook, which can be converted to other formats 197 | and printed. 198 | 199 | The \LaTeX\ source for this book is available from 200 | \url{https://github.com/LaurentRosenfeld/thinkperl6/} 201 | 202 | \vspace{0.2in} 203 | 204 | } % end small 205 | 206 | \end{latexonly} 207 | 208 | 209 | % HTMLONLY 210 | 211 | \begin{htmlonly} 212 | 213 | % TITLE PAGE FOR HTML VERSION 214 | 215 | {\Large \thetitle} 216 | 217 | {\large Laurent Rosenfeld, 218 | with Allen B. Downey} 219 | 220 | \theversion 221 | 222 | \thedate 223 | 224 | \setcounter{chapter}{-1} 225 | 226 | \end{htmlonly} 227 | 228 | \fi 229 | % END OF THE PART WE SKIP FOR PLASTEX 230 | 231 | % \include{preface.tex} 232 | \input{preface} 233 | 234 | % START THE BOOK 235 | \mainmatter 236 | 237 | \part{Starting with the Basics} 238 | 239 | \input{intro_part_1.tex} 240 | 241 | \input{chapt1} 242 | 243 | \input{chapt_var_expr} 244 | 245 | \input{chapt_func} 246 | 247 | \input{Conditional_and_recursion} 248 | 249 | \input{Fruitful_func} 250 | 251 | \input{iteration} 252 | 253 | \input{Strings} 254 | 255 | \input{wordplay} 256 | 257 | \input{Arrays} 258 | 259 | \input{hashes} 260 | 261 | \input{data_struct_selection} 262 | 263 | 264 | \part{Moving Forward} 265 | 266 | \include{intro_part_2} 267 | 268 | \input{objects} 269 | 270 | \input{grammars} 271 | 272 | \input{functional} 273 | 274 | \input{conclusion} 275 | 276 | \appendix 277 | 278 | \input{appendix_solutions} 279 | 280 | \printindex 281 | 282 | %\clearemptydoublepage 283 | %\clearemptydoublepage 284 | %\blankpage 285 | %\blankpage 286 | %\blankpage 287 | 288 | 289 | \end{document} 290 | -------------------------------------------------------------------------------- /book/up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LaurentRosenfeld/thinkperl6/8223c17d3437475e4e9602699b9348ee53c24c04/book/up.png --------------------------------------------------------------------------------