"What Does Your Code Smell Like?"で学ぶPerl6
-
Upload
risou -
Category
Technology
-
view
473 -
download
4
description
Transcript of "What Does Your Code Smell Like?"で学ぶPerl6
"What Does Your Code Smell Like?"で学ぶPerl6
by risouat yokohama.pm #9
はじめに
• 今回は Perl6 のお話をします• Perl6 に興味のない方は、15分の休憩と思ってゆっくりしてください。
YAPCお疲れ様でした
•面白くてタメになるトークがたくさん
•懇親会の美味しい料理
• LTthonのすごい盛り上がり
• etc...
ところで
Larry のトーク聴きましたか?
What Does Your Code Smell Like?
• strand sort を行うプログラム
• Perl5 のコードを Perl6 のコードへ
use 5.10.0; # for given/whensub merge { my ($x, $y) = @_; my @out; while (@$x and @$y) { given ($x->[-1] <=> $y->[-1]) { when( 1) { unshift @out, pop @$x } when(-1) { unshift @out, pop @$y } default { splice @out, 0, 0, pop(@$x), pop(@$y) } } } return @$x, @$y, @out}
sub strand { my $x = shift; my @out = shift @$x // return; if (@$x) { for (-@$x .. -1) { if ($x->[$_] >= $out[-1]) { push @out, splice @$x, $_, 1 } } } return @out}
sub strand_sort { my @x = @_; my @out; while (my @strand = strand(\@x)) { @out = merge(\@out, \@strand) } @out}
my @a = map (int rand(100), 1 .. 10);say "Before @a";@a = strand_sort(@a);say "After @a";
sub infix:<M> (@x is rw, @y is rw) { gather { while @x and @y { given @x[0] cmp @y[0] { when Increase { take @x.shift } when Decrease { take @y.shift } when Same { take @x.shift, @y.shift } } } take @x, @y }}
sub strand (@x is rw) { my $prev = -Inf; my $i = 0; gather while $i < @x { if @x[$i] before $prev { $i++; } else { take $prev = @x.splice($i, 1)[0]; } }}
sub strand_sort (@x is copy) { my @out; @out M= strand(@x) while @x; @out}
my @a = (^100).roll(10);say "Before @a[]";@a = strand_sort(@a);say "After @a[]";
@a = <The quick brown fox jumps over the lazy dog>;say "Before @a[]";@a = strand_sort(@a);say "After @a[]";
今回のお話
• “What Does Your Code Smell Like?”を元に Perl6 を紹介します
•(時間の都合で)全部は紹介しません
文法の違い
merge関数
sub merge { my ($x, $y) = @_; my @out; while (@$x and @$y) { given ($x->[-1] <=> $y->[-1]) { when( 1) { unshift @out, pop @$x } when(-1) { unshift @out, pop @$y } default { splice @out, 0, 0, pop(@$x), pop(@$y) } } } return @$x, @$y, @out}
シンタックスハイライトを変更
sub merge { my ($x, $y) = @_; my @out; while (@$x and @$y) { given ($x->[-1] <=> $y->[-1]) { when( 1) { unshift @out, pop @$x } when(-1) { unshift @out, pop @$y } default { splice @out, 0, 0, pop(@$x), pop(@$y) } } } return @$x, @$y, @out}
引数の受取り方が変わる
sub merge ($x, $y) {# my ($x, $y) = @_; my @out; while (@$x and @$y) { given ($x->[-1] <=> $y->[-1]) { when( 1) { unshift @out, pop @$x } when(-1) { unshift @out, pop @$y } default { splice @out, 0, 0, pop(@$x), pop(@$y) } } } return @$x, @$y, @out}
不要な括弧を除去
sub merge ($x, $y) {# my ($x, $y) = @_; my @out; while @$x and @$y { given $x->[-1] <=> $y->[-1] { when 1 { unshift @out, pop @$x } when -1 { unshift @out, pop @$y } default { splice @out, 0, 0, pop(@$x), pop(@$y) } } } return @$x, @$y, @out}
全ての変数がリファンレス
sub merge (@x, @y) {# my ($x, $y) = @_; my @out; while @x and @y { given $x[-1] <=> $y[-1] { when 1 { unshift @out, pop @x } when -1 { unshift @out, pop @y } default { splice @out, 0, 0, pop(@x), pop(@y) } } } return @x, @y, @out}
strand関数
sub strand { my $x = shift; my @out = shift @$x // return; if (@$x) { for (-@$x .. -1) { if ($x->[$_] >= $out[-1]) { push @out, splice @$x, $_, 1 } } } return @out}
シンタックスハイライトを変更
sub strand { my $x = shift; my @out = shift @$x // return; if (@$x) { for (-@$x .. -1) { if ($x->[$_] >= $out[-1]) { push @out, splice @$x, $_, 1 } } } return @out}
既に説明した変更を適用
sub strand (@x) { my @out = shift @x // return; if @x { for -@x .. -1 { if (@x[$_] >= @out[-1]) { push @out, splice @x, $_, 1 } } } return @out}
配列の添字にマイナスは使えない
sub strand (@x) { my @out = shift @x // return; if @x { for -@x .. -1 { if (@x[*+$_] >= @out[*-1]) { push @out, splice @x, *+$_, 1 } } } return @out}
範囲指定時の ^
sub strand (@x) { my @out = shift @x // return; if @x { for 0 ..^ @x { if (@x[$_] >= @out[*-1]) { push @out, splice @x, $_, 1 } } } return @out}
変更点まとめ
• 引数の受取り方が変わった• if, while 等の条件指定時に括弧が不要• 全ての変数がリファレンスに• 配列の添字に負数は使えない→代わりに whatever(*) を使う
• 範囲指定の .. に ^ をつけると、その値を除外( 0 ^..^ 3 => 1, 2 )
見慣れないキーワード
見慣れないものたち
sub infix:<M> (@x is rw, @y is rw) { gather { while @x and @y { given @x[0] cmp @y[0] { when Increase { take @x.shift } when Decrease { take @y.shift } when Same { take @x.shift, @y.shift } } } take @x, @y }}
infix:<M>
infix:<***>
•いわゆる中置演算子の定義
•引数を2つとる
sub infix:<exp> ($x, $y) { $x ** $y;}
say 3 exp 4; # 81
(例) べき乗の関数
sub infix:<M> (@x is rw, @y is rw) { gather { while @x and @y { given @x[0] cmp @y[0] { when Increase { take @x.shift } when Decrease { take @y.shift } when Same { take @x.shift, @y.shift } } } take @x, @y }}
こう定義して……
sub strand_sort (@x is copy) { my @out; @out = @out M strand(@x) while @x; @out;}
こう使う
sub strand_sort (@x is copy) { my @out; @out M= strand(@x) while @x; @out;}
こう書くこともできる
is rw
is ***
• Perl6 では引数は読み取り専用
•引数の値を変更したい場合は is rw
•引数のコピーが欲しい場合は is copy
sub writable ($x is rw) { $x += 1; say "x = $x";}
my $orig = 10;say "orig = $orig";writable($orig);say "orig = $orig";
# orig = 10# x = 11# orig = 11
is rw を使うと
sub copy_value ($x is copy) { $x += 1; say "x = $x";}
my $orig = 10;say "orig = $orig";copy_value($orig);say "orig = $orig";
# orig = 10# x = 11# orig = 10
is copy を使うと
sub read_only ($x) { $x += 1; say "x = $x";}
my $orig = 10;say "orig = $orig";read_only($orig);say "orig = $orig";
# orig = 10# Cannot assign to a readonly variable or a value# in block at src/gen/CORE.setting:11981# in sub read_only at is.pl:2# in block at is.pl:8
何も指定しなかった場合
gather ... take
gather ... take
• gather は遅延評価リストを返す
•評価時に gather ブロック内を走査
• take された要素を見つけて返す
my @list = gather { for 0 .. Inf { take $_ ** $_; }}
say @list[0..3]; # 1 1 4 27
簡単な例
sub infix:<M> (@x is rw, @y is rw) { gather { while @x and @y { given @x[0] cmp @y[0] { when Increase { take @x.shift } when Decrease { take @y.shift } when Same { take @x.shift, @y.shift } } } take @x, @y }}
merge関数での使い方
まとめ
• 文法にちょっとした変更がたくさん• 演算子を定義できる• is *** で引数へのアクセスレベルを指定• 遅延評価ができる
ところで
Perl5 と Perl6 の関係
• 異なる言語• Perl6 は Perl5 をベースに設計されている• Perl6 の特徴の一部は Perl5 に移植されている
Perl6::Gather
use strict;use warnings;
use Perl6::Gather;
my @list = gather { for (0..100) { take $_ ** $_; }};
for (0..3) { print $list[$_], ' ';}print "\n";
# 1 1 4 27