こんにちは
Perl 6 Advent Calendar 2016の7日目です。
昨日は @titsuki さんの 「初めてのInline::Perl5」でした。1
今日は、他の言語の人にPerl6を知ってもらおうという気持ちで、基本的な文法について Python3 と Perl6 を並べてみたいと思います。2
環境情報
# Mac のバージョン
$ sw_vers
ProductName: Mac OS X
ProductVersion: 10.12.1
BuildVersion: 16B2555
# Perl6 のバージョン
$ perl6 -v
This is Rakudo version 2016.11 built on MoarVM version 2016.11
implementing Perl 6.c.
# Python3 のバージョン
$ python3 --version
Python 3.5.1 :: Anaconda 4.1.0 (x86_64)
算術計算
print(1 - 2) #=> -1
print(4 * 5) #=> 20
print(7 / 5) #=> 1.4
print(3 ** 2) #=> 9
use v6;
say 1 - 2 ; #=> -1
say 4 * 5 ; #=> 20
say 7 / 5 ; #=> 1.4
say 3 ** 2 ; #=> 9
セミコロン(;
)の前に半角スペースを入れているのは趣味です。
データ型
の調べ方
print(type(10)) #=> <class 'int'>
print(type(2.718)) #=> <class 'float'>
print(type("hello")) #=> <class 'float'>
use v6;
say 10.WHAT ; #=> (Int)
say 2.718.WHAT ; #=> (Rat)
say "hello".WHAT ; #=> (Str)
10.^name.say ; #=> Int
2.718.^name.say ; #=> Rat
"hello".^name.say ; #=> Str
WHAT
(直球)
変数
動的型付け
# 初期化
x = 10
y = 3.14
print('%d is %s.' % (x, type(x))) #=> 10 is <class 'int'>.
# 代入
x = x * y
print('%.1f is %s.' % (x, type(x))) #=> 31.4 is <class 'float'>.
Perl6では1つの値が入る変数(スカラー変数)の先頭には$
を付けます。
use v6;
# 初期化
my $x = 10 ;
my $y = 3.14 ;
say $x ~ ' is ' ~ $x.^name ~ '.' ; #=> 10 is Int.
# 代入
$x = $x * $y ;
say sprintf '%.1f is %s.', $x, $x.^name ; #=> 31.4 is Rat.
Perl6は静的型付けもできます。
use v6;
# 型を指定して初期化
my Int $x = 10 ;
my Rat $y = 3.14 ;
# Int型の$xへのRat型の値代入はエラーになる
# $x = $x * $y ;
# Int型にすれば代入できる
$x = ($x * $y).Int ;
say $x ~ ' is ' ~ $x.^name ~ '.' ; #=> 31 is Int.
Perl5 では .
を使っていた文字列連結が、Perl6 では ~
を使うようになりました。
リスト
# リストの作成
a = [1, 2, 3, 4, 5]
# リストの中身を出力する
print(a) #=> [1, 2, 3, 4, 5]
# リストの長さを取得
print(len(a)) #=> 5
# 先頭の要素にアクセス
print(a[0]) #=> 1
# 末尾の要素にアクセス
print(a[-1]) #=> 5
# 値を代入
a[4] = 99
print(a) #=> [1, 2, 3, 4, 99]
# インデックスの0番目から2つ取得
print(a[0:2]) #=> [1, 2]
# インデックスの1番目から最後まで取得
print(a[1:]) #=> [2, 3, 4, 99]
# インデックスの最初から3つ取得
print(a[:3]) #=> [1, 2, 3]
# 最初から、最後の要素の1つ前まで取得
print(a[:-1]) #=> [1, 2, 3, 4]
Perl6では配列の変数の先頭には@
を付けます。
use v6;
# 配列の作成
my Int @a = < 1 2 3 4 5 > ;
# 配列の中身を出力する
say @a ; #=> [1 2 3 4 5]
# 配列の長さを取得
say @a.elems ; #=> 5
# 先頭の要素にアクセス
say @a[0] ; #=> 1
# 末尾の要素にアクセス
say @a[*-1] ; #=> 5
# 値を代入
@a[4] = 99 ;
@a.say ; #=> [1 2 3 4 99]
# インデックスの0番目から2つ取得
say @a.head(2).Array ; #=> [1 2]
# インデックスの1番目から最後まで取得
say @a[1..*].Array ; #=> [2 3 4 99]
# インデックスの最初から3つ取得
say @a.head(3).Array ; #=> [1 2 3]
say @a[^3].Array ; #=> [1 2 3]
# 最初から、最後の要素の1つ前まで取得
say @a[0..^*-1].Array ; #=> [1 2 3 4]
say @a[0..*-2].Array ; #=> [1 2 3 4]
※ Perl6の操作でList型が返却されるものについて、一応Array型に変換しています。
ディクショナリ
# ディクショナリを作成
me = {'height':180}
# 要素にアクセス
print(me['height']) #=> 180
# 新しい要素を追加
me['weight'] = 70
print(me) #=> {'weight': 70, 'height': 180}
Perl6ではこういうのをハッシュと呼んで、先頭には%
を付けます。
use v6;
# ハッシュを作成
my %me = 'height' => 180 ;
# 要素にアクセス
say %me{'height'} ; #=> 180
# 新しい要素を追加
%me{'weight'} = 70 ;
say %me ; #=> {height => 180, weight => 70}
ブーリアン
hungry = True
sleepy = False
print(type(hungry)) #=> <class 'bool'>
print(not hungry) #=> False
print(hungry and sleepy) #=> False
print(hungry or sleepy) #=> True
use v6;
my Bool $hungry = True ;
my Bool $sleepy = False ;
say $hungry.^name ; #=> Bool
say not $hungry ; #=> False
say ( $hungry and $sleepy ) ; #=> False
say ( $hungry or $sleepy ) ; #=> True
ちゃんとBoolean型があるなんて、なんて素晴らしい言語なんだ
if文
hungry = True
if hungry:
print("I'm hungry")
hungry = False
if hungry:
print("I'm hungry")
else:
print("I'm not hungry")
use v6;
my Bool $hungry = True ;
if $hungry {
say "I'm hungry" ;
}
$hungry = False ;
if $hungry {
say "I'm hungry" ;
}
else {
say "I'm not hungry" ;
}
for文
for i in [1, 2, 3]:
print(i)
use v6;
for 1, 2, 3 -> $i {
say $i ;
}
余談ですが、Perl5 では以下のように書いてました。
use v5;
for my $i (1, 2, 3) {
print $i . "\n" ;
}
for文に関しては Perl6 より Python3 の方が Perl5 に似てる感。
関数
def hello():
print("Hello World!")
hello() #=> Hello World!
def hello2(object):
print("Hello " + object + "!")
hello2("Neighbor") #=> Hello Neighbor!
( これ、 object
が文字列型じゃなかったら文字列連結でエラーになるのではないだろうか )
use v6;
my sub hello {
say "Hello World!" ;
}
hello() #=> Hello World!
my sub hello2(Str $object) {
say "Hello " ~ $object ~ "!" ;
}
hello2("Neighbor") #=> Hello Neighbor!
引数は文字列型に限定しています。
クラス
class Man:
def __init__(self, name):
self.name = name
print("Initialized!")
def hello(self):
print("Hello " + self.name + "!")
def goodbye(self):
print("Good-bye " + self.name + "!")
m = Man("Alice")
m.hello()
m.goodbye()
use v6;
my class Man {
has Str $.name is readonly;
method new(Str $name){
say "Initialized!" ;
return self.bless(:$name) ;
}
method hello {
say "Hello " ~ self.name ~ "!" ;
}
method goodbye {
say "Good-bye " ~ self.name ~ "!" ;
}
}
my $m = Man.new("Alice") ;
$m.hello ;
$m.goodbye ;
上記では引数の指定方法をPython版に合わせるためにコンストラクタを再定義しましたが、普通はこんな感じで書くかもしれません。
use v6;
my class Man {
has Str $.name is required;
method hello {
say "Hello " ~ self.name ~ "!" ;
}
method goodbye {
say "Good-bye " ~ self.name ~ "!" ;
}
}
my Man $m .= new(name => "Alice") ;
$m.hello ;
$m.goodbye ;
おわり
他の言語と並べてみると、似ているところとか、逆にものすごくPerl6独特なところがあって面白いですね
参考と注釈
-
昨年のアドベントカレンダーでInline::Perl5ネタ書こうと思ったらインストールに失敗した…という思い出がよみがえりました。 ↩
-
Pythonのコードは ゼロから作るDeep Learning の
1章 Python入門
を参考にしました。 ↩