Perl6のif文は空白が重要

Perl6でこういったコードを書くと

#!/usr/bin/env perl6
use v6;

if ( 1 ){
    say "goe";
}
perl6 if.p6
===SORRY!=== Error while compiling /Users/anatofuz/workspace/cr/Basic/perl6/sandbox/log/if.p6
Missing block (whitespace needed before curlies taken as a hash subscript?)
at /Users/anatofuz/workspace/cr/Basic/perl6/sandbox/log/if.p6:8
------> <BOL>⏏<EOL>
    expecting any of:
        block or pointy block

とエラーが発生する. これは ifの後の (){ の間に空白がない為であり

#!/usr/bin/env perl6
use v6;

if ( 1 ) {
    say "goe";
}

としてあげると

perl6 if.p6
goe

と表示される

公式ドキュメントを見るとif文には ()をつけないで書いている為言語デザイナー的には

ifと評価する真偽値の間には区切りの空白があるのは当然だけれども,()はあくまで人間が見やすくしているだけなので空白入れてくれ!!という世界観だと思った.

Perl6の正規表現の世界 ~ キャプチャマーカー編 ~

こんにちは.最近Perl6に思いを馳せつつRubyソースコードを読んだりしているid:anatofuzです. ところで9月はOkinawa.pmとRoppongi.pmが開催される予定なので皆さんよろしくお願いします.

題材

さて今回ですが個人的にPerl6のスピードを他言語と比較測定しようとしています. 題材として青空文庫から正規表現で漢字とふりがなを取り出すというスクリプトを作成しています.

どういうことかというと青空文庫テキスト版は蜜蜂《みつばち》の用に漢字+<<>>の順でるびが表記されています. これを正規表現でキャプチャするには例えばPerl5の場合

#!/usr/bin/env perl
use strict;
use warnings;
use utf8;
use feature 'say';
use Encode;

my $filename = "./dogura_magura.txt";
open my $fh,'<:encoding(utf-8)',$filename or die qw/can't open/;

my @kana;

while (my $line = <$fh>) {
    chomp $line;
    while( $line =~ m![、。]?(\p{Han}+)(\p{Hiragana}+)!g){
        push @kana,[$1,$2];
    }
}

print scalar @kana;

この場合 m![、。]?(\p{Han}+)《(\p{Hiragana}+)》!unicodeプロパティを使ってキャプチャしています. ちなみにRubyで書くとこんな感じです

#!/usr/bin/env ruby

File.open("./dogura_magura.txt",'r') do |f|
    hoge = f.read.scan(/[、。]?(\p{Han}+)(\p{Hiragana}+)/)
    p hoge.count
end

Perl6で書く

ではこれをPerl6で書いてみましょう

#!/usr/bin/env perl6
use v6;

my $file = "./dogura_magura.txt";
my $fh = open $file, :r;
my $hoge;

for $fh.lines -> $line {
    if ($line ~~ m:g/<[、。]>?(<:Han>+)""(<:Hiragana>+)""/ ) {
        say $/[0];
        $hoge += $/.conj;
    }
}

say $hoge;

$fh.close;

Perl6の場合正規表現がPerl5と大分異なっており,まず文字クラスは[]ではなく<[]>と表記します. Unicodeプロパティは<:プロパティ名>と表記し,文字列はダブルクォーテーションでくくる必要があります.

実際にこれでコードを実行すると

# say $0;
「蜜蜂《みつばち》」
 0 => 「蜜蜂」
 1 => 「みつばち」

こういった具合に $0に配列としてキャプチャ結果が代入されます. なぜ配列で$0から入るかはこちらの資料を御覧ください.

qiita.com

キャプチャマーカー

さて本題です.

Perl6の正規表現にはキャプチャマーカー(Capture markers)と呼ばれる機能があります. 構文的には <()>と書くとキャプチャマーカーです.

公式ドキュメントによれば以下のように書かれています.

A <( token indicates the start of the match's overall capture, while the corresponding )> token indicates its endpoint. The <( is similar to other languages \K to discard any matches found before the \K.

 say 'abc' ~~ / a <( b )> c/;            # OUTPUT: «「b」␤» 
 say 'abc' ~~ / <(a <( b )> c)>/;        # OUTPUT: «「bc」␤» 

As the example above, you can see <( sets the start point and )> sets the endpoint; since they are actually independent each other, the inner-most start point wins (the one attache to b) and the outer-most end wins (the one attached to c).

CaptureMarkers%3E)

つまりこれはどういうことかというと 「正規表現の開始位置と終了位置を書き換えることが可能」という訳です.

二番目の例を見てみましょう

 say 'abc' ~~ / <(a <( b )> c)>/;        # OUTPUT: «「bc」␤» 

こちらはまず内部の <(b)>のキャプチャマーカーが処理され,abcという文字列の中のbがキャプチャされます. キャプチャマーカーではこの時点でキャプチャが走り,キャプチャマーカーはエンドポイントであるbcという文字列を返します. 次のキャプチャではこの末尾のcがキャプチャされるので全体的なアウトプットは bcとなります.

青空文庫の例

ではこれを応用(?)してみましょう.

先程の青空文庫正規表現で後ろのかなの部分にキャプチャマーカーを当てます

 m:g/<[、。]>?(<:Han>+)"《"<(<:Hiragana>+)>"》"/

こうするとどうなるでしょうか. 答えはこのようになります.

「みつばち」
 0 => 「蜜蜂」

挙動を確認するとまずキャプチャマーカーでかなの部分が読み込まれます. 読み込まれた場所はPerl6は利用しないで捨てられます.

続いてキャプチャする箇所が前にあるのでPerl6はキャプチャを後ろに戻し漢字の箇所をキャプチャし返却します.

なかなかの挙動でしたね.正直使いこなせるのか怪しいところがあります.

ちなみにこれは吉祥寺.pmのid:magnoliakさんと探っていました. 常日頃からコラボしている吉祥寺.pmとOkinawa.pmのコラボpm Roppongi.pmは9月開催予定なのでよろしくお願いします

Hackers-Champloo 2018 で(スタッフ|LT)してきました

こんにちは id:anatofuz です.久しくイベント参加ブログを書いていない(最悪)なのですが忘れないうちに書きます.

ハカチャンでの役割

今回のハカチャンではSNS運用おじさん+Okinawa.pmの人という感じで関わらせていただきました. SNS運用おじさんはYAPC::Okinawaでも行っていたので前回の知見を使いながら行っていました.

個人的に一番貢献できたかなというのはOkinawa.pmとしてPerl界隈の人をゲストとして打診するというフェーズで 前々から思っていた「個人的にid:motemenさん呼びたい」という案を実行委員帳の西島さんからOKをもらい,実行したところです.

motemenさんを呼びたかったのは個人的にはてなインターンでの思いがあるということと,単純に僕がお会いしたかったからという所です. 打診した所OKを頂き,無事Okinawa.pmの人として役目を果たせたと思っています.

トーク

トークハッカーズチャンプルーらしく様々な方面のトークが聞け,非常に良かったです. 今回はゲーム方面としてUnityの方もお呼びしていましたが,学生にとっては身近な話題だったので参加者層とマッチしており,運営が功を奏したと思っています.

参加者の中に僕の学科*1の1年次が多く,この時期からカンファレンスに参加できるのは良いなと感じました. そういえば僕が最初に参加したカンファレンスもハカチャンだったことを思い出し,懐かしい思いになりました.

どのトークも非常に良かったのですが,個人的な話をするとやはりお呼びしたmotemenさんのトークが聞けて良かったと思っています. 去年のインターンの後様々な思いがあり,色々と辛かったことも多かったのですが,トークを聞いてなんというか救われた感じがしました. motemenさんとは懇親会でも色々とお話する事ができて,自分としてはこの上ないほど良い体験をさせていただきました. id:motemenさんご登壇していただいてありがとうございました!

(これは余談ですがハカチャンに来ていた大学の先生が去年のインターンのブログエントリを見ることを1年時に進めていたらしい)

LT

LT芸人のようなところがあるので今回もLTしました.

ちなみにスライドのこの部分ですが

休憩時間にメルカリからきていたid:codehexさんから「遠慮せずにOkinawa.pm開催したほうが良い」と言われその場の勢いで決定したものです.

言ったからにはやろうと思っていて,確実に9月には開催する予定です.それまでの7,8月なのは短めにやると思います.

来年へ

ハッカーズチャンプルー毎年非常に良いイベントになっていて,今年は運営としてちょっとお手伝いさせていただいたので個人的には今までで一番良かったかなと思っています.来年も運営としてお手伝いさせていただこうと思っていますので皆さんよろしくお願いします.

*1:琉大情報工学

Perl6とnqpのプロファイルを出力する

TL;DR

$nqp --profile colon-pair.nqp

基本はこのLearningPerl6の記事を見れば良いのだが,Perl6が動いているMoarVMにはbuilt-inでプロファイラが用意されている. 基本的にはDevel::NYTProfと似た雰囲気でプロファイラが出力される.

例えば下の通り

MoarVM Profiler Results

今の所見た目は良いがDevel::NYTProfほどいい感じにトレースが出来ない気がしている.

公式ドキュメントによるとなんと SQLでプロファイル結果を出力 することが出来るらしい.

.gitignoreの中に.gitignoreを書く

TL;DR

.gitignoreの中に.gitignoreを書くことで.gitignoreを管理下におかず実現できる

gitignroeをgithubリポジトリにpushしたくないが,gitの管理から外したい物がある時は 循環のようにgitignoreを書いておくと行ける

cpanfile.snapshot
local/
.gitignore

みたいな感じ


追記 2018/05/24

id:karupanerura さんより .git/info/exclude に書くと同等のことが出来るらしいです!

cf.

Ignoring files - User Documentation

意外と使えるcd - とdirsコマンド

意外と使えるけれどみんなあまり知らないlinuxコマンドテクニックです

TL;DR

cd -

普段ディレクトリを移動する際は cd を使いますが,引数として-を与えてあげると違った挙動をします.

例えば最初にルートディレクトリに移動,次にホームディレクトリ以下のsadboxに移動してみます

 / ❯❯❯ cd /
/ ❯❯❯ ls
Applications              Volumes                   home                      sbin
Library                   bin                       installer.failurerequests tmp
Network                   cores                     net                       usr
System                    dev                       opt                       var
Users                     etc                       private
/ ❯❯❯ cd ~/.sandbox
~/.sandbox ❯❯❯ ls
1.aux                     1.out                     Gemfile                   missfont.log
1.dvi                     1.pdf                     Gemfile.lock              naltoma.txt
1.fdb_latexmk             1.synctex.gz              a.out                     prezto-fasd-cache.501.zsh
1.fls                     1.tex                     hoge.c                    texrepo
1.log                     1.toc                     hoge.rb                   vendor
~/.sandbox ❯❯❯ pwd
/Users/anatofuz/.sandbox
~/.sandbox ❯❯❯ cd -
/
/ ❯❯❯ pwd
/
/ ❯❯❯ cd -
~/.sandbox
~/.sandbox ❯❯❯ pwd
/Users/anatofuz/.sandbox

こういった用に cd -を使うと直前のディレクトリを行き来する事が可能です.

dirs

ディレクトリを移動する際に,現在いるカレントディレクトリがディレクトリスタックというスタックに保存されます. スタックとはFirst In Last Out(FILO)とも呼ばれ,つまり最初に入ったやつが最後に出てくるデータ構造です.

例えばディレクトリスタックが次のようになっている場合

dirs                                                                                                      [20:14:04]
~ ~/.sandbox ~/workspace/github ~/workspace

これは最初に ~/workspaceにcdし,次に ~/workspace/githubにcdを行い, 続いて ~/.sandboxにcdした後に最後にホームディレクトリに移動したことを表しています.一番左が現在のカレントディレクトリで,時系列的に右に進むと良いということがわかります.

例えば

 anatofuz@anatofuz  ~/.sandbox 
 ❯ cd                                                                                                        [20:18:55]

 anatofuz@anatofuz  ~ 
 ❯ dirs                                                                                                      [20:18:56]
~ ~/.sandbox ~/workspace/github ~/workspace

 anatofuz@anatofuz  ~ 
 ❯ cd workspace/bitbucket                                                                                    [20:19:03]

 anatofuz@anatofuz  ~/w/bitbucket 
 ❯ dirs                                                                                                      [20:19:04]
~/workspace/bitbucket ~ ~/.sandbox ~/workspace/github ~/workspace

この用に移動するとカレントディレクトリがディレクトリスタックに詰まっていきます. これはvオプションを付けるとよりわかりやすくなるかと思います.

dirs -v                                                                                                   [20:13:10]
0  ~
1  ~/.sandbox
2  ~/workspace/github
3  ~/workspace

これで言うところの0が現在のカレントディレクトリ.3が最初にcdした先ですね.

popd

このディレクトリスタックをpopつまり一番最近のものを取り出していくのがpopdコマンドです.

先程の状況で検証してみると

 ❯ pwd                                                                                                       [20:23:37]
/Users/anatofuz

 anatofuz@anatofuz  ~ 
 ❯ popd                                                                                                      [20:23:38]

 anatofuz@anatofuz  ~/.sandbox 
 ❯ pwd                                                                                                       [20:23:39]
/Users/anatofuz/.sandbox

 anatofuz@anatofuz  ~/.sandbox 
 ❯ popd                                                                                                      [20:23:40]

 anatofuz@anatofuz  ~/w/github 
 ❯ pwd                                                                                                       [20:23:41]
/Users/anatofuz/workspace/github

この用に順にディレクトリが移動していっています. なお + 2などつけるとその分ディレクトリが消されます

pushd

pushdはその逆で,カレントディレクトリをディレクトリスタックに積み上げます

zshなら

zshならオプションで設定する必要がありますが, cd -でタブを押すことで ディレクトリスタックが可視化され,簡単にcdする事ができます.

f:id:anatofuz:20180518200330p:plain

 ❯ dirs                                                                                                      [20:02:51]
~ ~/.sandbox ~/workspace/github ~/workspace

 anatofuz@anatofuz  ~ 
 ❯ cd -0/                                                                                                    [20:02:51]
 -- directory stack --
0 -- ~/workspace
1 -- ~/workspace/github
2 -- ~/.sandbox