Perl6 と Python3 の基本的な文法を並べてみる

こんにちは:whale2:
[Perl 6 Advent Calendar 2016](http://qiita.com/advent-calendar/2016/perl6)の7日目です。
昨日は @titsuki さんの 「[初めてのInline::Perl5](http://qiita.com/titsuki/items/0ee508c93d7bff149916)」でした。[^memory]

今日は、他の言語の人にPerl6を知ってもらおうという気持ちで、基本的な文法について Python3 と Perl6 を並べてみたいと思います。[^sample]

## 環境情報

```bash
# Mac のバージョン
$ sw_vers
ProductName:	Mac OS X
ProductVersion:	10.12.1
BuildVersion:	16B2555
```

```bash
# Perl6 のバージョン
$ perl6 -v
This is Rakudo version 2016.11 built on MoarVM version 2016.11
implementing Perl 6.c.
```

```bash
# Python3 のバージョン
$ python3 --version
Python 3.5.1 :: Anaconda 4.1.0 (x86_64)
```

## 算術計算

```py3:Python3
print(1 - 2) #=> -1
print(4 * 5) #=> 20
print(7 / 5) #=> 1.4
print(3 ** 2) #=> 9
```

```pl:Perl6
use v6;
say 1 - 2 ; #=> -1
say 4 * 5 ; #=> 20
say 7 / 5 ; #=> 1.4
say 3 ** 2 ; #=> 9
```
セミコロン(`;`)の前に半角スペースを入れているのは趣味です。

## データ型
の調べ方

```py3:Python3
print(type(10)) #=> <class 'int'>
print(type(2.718)) #=> <class 'float'>
print(type("hello")) #=> <class 'float'>
```

```pl:Perl6
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`(直球)

## 変数
動的型付け

```py3:Python3
# 初期化
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つの値が入る変数(スカラー変数)の先頭には`$`を付けます。

```pl:Perl6
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は[静的型付けもできます](http://ja.perl6intro.com/#_型)。

```pl: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 では `~` を使うようになりました。

## リスト

```py3:Python3
# リストの作成
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では配列の変数の先頭には`@`を付けます。

```pl: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型に変換しています。

## ディクショナリ

```py3:Python3
# ディクショナリを作成
me = {'height':180}

# 要素にアクセス
print(me['height']) #=> 180

# 新しい要素を追加
me['weight'] = 70
print(me) #=> {'weight': 70, 'height': 180}
```

Perl6ではこういうのをハッシュと呼んで、先頭には`%`を付けます。

```pl:Perl6
use v6;
# ハッシュを作成
my %me = 'height' => 180 ;

# 要素にアクセス
say %me{'height'} ; #=> 180

# 新しい要素を追加
%me{'weight'} = 70 ;
say %me ; #=> {height => 180, weight => 70}
```

## ブーリアン

```py3:Python3
hungry = True
sleepy = False

print(type(hungry)) #=> <class 'bool'>
print(not hungry) #=> False
print(hungry and sleepy) #=> False
print(hungry or sleepy) #=> True
```

```pl:Perl6
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文

```py3:Python3
hungry = True
if hungry:
    print("I'm hungry")

hungry = False
if hungry:
    print("I'm hungry")
else:
    print("I'm not hungry")
```

```pl:Perl6
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文

```py3:Python3
for i in [1, 2, 3]:
    print(i)
```

```pl:Perl6
use v6;
for 1, 2, 3 -> $i {
    say $i ;
}
```

余談ですが、Perl5 では以下のように書いてました。

```pl:Perl5
use v5;
for my $i (1, 2, 3) {
    print $i . "\n" ;
}
```

for文に関しては Perl6 より Python3 の方が Perl5 に似てる感。

## 関数

```py3:Python3
def hello():
    print("Hello World!")

hello() #=> Hello World!

def hello2(object):
    print("Hello " + object + "!")

hello2("Neighbor") #=> Hello Neighbor!
```

( これ、 `object` が文字列型じゃなかったら文字列連結でエラーになるのではないだろうか )


```pl:Perl6
use v6;
my sub hello {
    say "Hello World!" ;
}

hello() #=> Hello World!

my sub hello2(Str $object) {
    say "Hello " ~ $object ~ "!" ;
}

hello2("Neighbor") #=> Hello Neighbor!
```

引数は文字列型に限定しています。

## クラス

```py3:Python3
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()
```

```pl:Perl6
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版に合わせるためにコンストラクタを再定義しましたが、普通はこんな感じで書くかもしれません。

```pl:Perl6
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独特なところがあって面白いですね:camel:

## 参考と注釈

* [ゼロから作るDeep Learning](https://www.oreilly.co.jp/books/9784873117584/)
* [Array](https://docs.perl6.org/type/Array)
* [Hash](https://docs.perl6.org/type/Hash)

[^memory]: 昨年のアドベントカレンダーでInline::Perl5ネタ書こうと思ったらインストールに失敗した…という思い出がよみがえりました。
[^sample]: Pythonのコードは [ゼロから作るDeep Learning](https://www.oreilly.co.jp/books/9784873117584/) の`1章 Python入門`を参考にしました。