スキップしてメイン コンテンツに移動

Perl 5 to 6 - サブルーチンとシグネチャ

これはMoritz Lenz氏のWebサイトPerlgeek.deで公開されているブログ記事"Perl 5 to 6" Lesson 04 - Subroutines and Signaturesの日本語訳です。

原文はCreative Commons Attribution 3.0 Germanyに基づいて公開されています。

本エントリにはCreative Commons Attribution 3.0 Unportedを適用します。

Original text: Copyright© 2008-2010 Moritz Lenz

Japanese translation: Copyright© 2011 SATOH Koichi

NAME

"Perl 5 to 6" Lesson 04 - サブルーチンとシグネチャ

SYNOPSIS

# シグネチャなしのサブルーチン——Perl5風
sub print_arguments {
    say "Arguments:";
    for @_ {
        say "\t$_";
    }
}

# 固定引数の型指定付きシグネチャ
sub distance(Int $x1, Int $y1, Int $x2, Int $y2) {
    return sqrt ($x2-$x1)**2 + ($y2-$y1)**2;
}
say distance(3, 5, 0, 1); 

# デフォルト引数
sub logarithm($num, $base = 2.7183) {
    return log($num) / log($base)
}
say logarithm(4);       # 第2引数はデフォルトを利用
say logarithm(4, 2);    # 明示的な第2引数

# 名前付き引数
sub doit(:$when, :$what) {
    say "doing $what at $when";
}
doit(what => 'stuff', when => 'once');  # 'doing stuff at once'
doit(:when<noon>, :what('more stuff')); # 'doing more stuff at noon'
# 不正: doit("stuff", "now")

DESCRIPTION

サブルーチンはsubキーワードで宣言され、CやJavaその他の言語と同様に形式的パラメータを持ちます。これらのパラメータは型制約をとることもできます。

パラメータはデフォルトでは読み出し専用です。この挙動はいわゆる「Trait」で変更できます:

sub foo($bar) {
    $bar = 2;       # 禁止されている
}

my $x = 2;
sub baz($bar is rw) {
    $bar = 0;       # 許される
}
baz($x); say $x;    # 0

sub quox($bar is copy){
    $bar = 3;
}
quox($x); say $x    # まだ0

パラメータは?を後ろに付けたり、デフォルト値を与えることでオプションにできます。

sub foo($x, $y?) {
    if $y.defined {
        say "WE CAN HAZ $y"
    }
}

sub bar($x, $y = 2 * $x) { 
    ...
}

名前付きパラメータ

my_sub($first, $second)のようにしてサブルーチンを呼び出すとき、$firstは最初の形式的パラメータに、$secondは2番目の形式的パラメータに、といった具合に結びつきます。このようなパラメータを「位置的」パラメータと呼んでいます。

数を数えるより名前を思い出す方が簡単なことは往々にしてあるので、Perl6は名前付きパラメータも持っています:

my $r = Rectangle.new( 
        x       => 100, 
        y       => 200, 
        height => 23,
        width  => 42,
        color  => 'black'
);

引数が具体的に何を意味しているか、見るなりすぐに理解できます。

名前付きパラメータを定義するには、単にパラメータの前に:を置くだけです:

sub area(:$width, :$height) {
    return $width * $height;
}
area(width => 2,  height => 3);
area(height => 3, width => 2 ); # 同じ
area(:height(3), :width(2));    # 同じ

ここまでの例では変数名がパラメータの名前としても使われていますが、別の名前を使うこともできます:

sub area(:width($w), :height($h)){
    return $w * $h;
}
area(width => 2,  height => 3);

名前付き引数は名前を使ってのみ渡すことができ、位置による指定はできません。一方で位置的引数は名前を使って渡すこともできます:

sub sqrt($number) { ... };
sqrt(3);
sqrt(number => 3); # これも動く

丸呑み(Slurpy)引数

サブルーチンにシグネチャを付けることは、前もって引数の数を知っておかなければならないということではありません。 残された引数を使い切る、丸呑み(slurpy)パラメータを(通常のパラメータの後に)定義することができます:

sub tail ($first, *@rest){
    say "First: $first";
    say "Rest: @rest[]";
}
tail(1, 2, 3, 4);           # "First: 1\nRest: 2 3 4\n"

変数展開

デフォルトでは配列は引数リストに展開されません。したがってPerl5とは異なり次のようなコードが書けます:

sub a($scalar1, @list, $scalar2){
    say $scalar2;
}

my @list = "foo", "bar";
a(1, @list, 2);                  # 2

これはデフォルトではリストを引数リストとして使えないということでもあります:

my @indexes = 1, 4;
say "abc".substr(@indexes)       # エラー!

プレフィクス|を付けると期待した動作をします:

say "abcdefgh".substr(|@indexes) # bcde

多重サブルーチン

異なるパラメータリストを持つ同名のサブルーチンを複数定義できます:

multi sub my_substr($str) { ... }                          # 1
multi sub my_substr($str, $start) { ... }                  # 2
multi sub my_substr($str, $start, $end) { ... }            # 3
multi sub my_substr($str, $start, $end, $subst) { ... }    # 4

このようなサブルーチンを呼び出すと、パラメータリストが一致するものが選ばれます。

多重サブルーチンは引数の数で区別できる必要はなく、パラメータの型でも区別します:

multi sub frob(Str $s) { say "Frobbing String $s"  }
multi sub frob(Int $i) { say "Frobbing Integer $i" }

frob("x")       # Frobbing String x
frob(2)         # Frobbing Integer 2

MOTIVATION

明示的な型シグネチャの有用性を疑う人はいません: タイピング量は削減され、重複引数の確認は省け、より自己文書化されたコードになります。 名前付きパラメータの価値も既に議論され切っています。

これはまた有用なイントロスペクションを提供します。例えばブロックかサブルーチンをArray.sortに渡したとして、そのコードが1つだけ引数を取るとすると、シュワルツ変換が自動的に行われます——このような機能はPerl5では不可能でした。明示的なシグネチャを欠いているため、sortはコードブロックが何個の引数を取るのか判断できないからです。

多重サブルーチンは組み込み関数を新しい型に対してオーバーライドできるという点で非常に便利です。例えばあなたが(大文字と小文字の変換に独特の規則がある)トルコ語の文字列を正しく扱えるようにローカライズされたバージョンのPerl6を欲しがっているとしましょう。

言語を改変する代わりに単にTurkishStrという新しい型を導入し、組み込み関数に多重サブルーチンを追加するだけです:

multi uc(TurkishStr $s) { ... }

これで文字列が言語に対応した型を持っているかだけ気をつければ、ucを通常の組み込み関数のように使えます。

演算子もサブルーチンなので、これらの改善点は演算子についても同様に働きます。

SEE ALSO

http://perlcabal.org/syn/S06.html

コメント

このブログの人気の投稿

Perl 7 より先に Perl 5.34 が出るぞという話

Perl 5 の次期バージョンとして一部後方互換でない変更 (主に間接オブジェクト記法の削除とベストプラクティスのデフォルトでの有効化) を含んだメジャーバージョンアップである Perl 7 がアナウンスされたのは昨年の 6 月 のことだったが、その前に Perl 5 の次期周期リリースである Perl 5.34 が 5 月にリリース予定 である。 現在開発版は Perl 5.33.8 がリリースされておりユーザから見える変更は凍結、4 月下旬の 5.33.9 で全コードが凍結され 5 月下旬に 5.34.0 としてリリース予定とのこと。 そういうわけで事前に新機能の予習をしておく。 8進数数値リテラルの新構文 見た瞬間「マジかよ」と口に出た。これまで Perl はプレフィクス 0 がついた数値リテラルを8進数と見做してきたが、プレフィクスに 0o (zero, small o) も使えるようになる。 もちろんこれは2進数リテラルの 0b や 16進数リテラルの 0x との一貫性のためである。リテラルと同じ解釈で文字列を数値に変換する組み込み関数 oct も` 新構文を解するようになる。 昨今無数の言語に取り入れられているリテラル記法ではあるが、この記法の問題は o (small o) と 0 (zero) の区別が難しいことで、より悪いことに大文字も合法である: 0O755 Try / Catch 構文 Perl 5 のリリース以来 30 年ほど待たれた実験的「新機能」である。 Perl 5 における例外処理が特別な構文でなかったのは予約語を増やさない配慮だったはずだが、TryCatch とか Try::Tiny のようなモジュールが氾濫して当初の意図が無意味になったというのもあるかも知れない。 use feature qw/ try / ; no warnings qw/ experimental::try / ; try { failable_operation(); } catch ( $e ) { recover_from_error( $e ); } Raku (former Perl 6) だと CATCH (大文字なことに注意) ブロックが自分の宣言されたスコープ内で投げられた例外を捕らえる

BuckleScript が ReScript に改称し独自言語を導入した

Via: BuckleScript Good and Bad News - Psellos OCaml / ReasonML 文法と標準ライブラリを採用した JavaScript トランスパイラである BuckleScript が ReScript に改称した。 公式サイトによると改称の理由は、 Unifying the tools in one coherent platform and core team allows us to build features that wouldn’t be possible in the original BuckleScript + Reason setup. (単一のプラットフォームとコアチームにツールを統合することで従来の BuckleScript + Reason 体制では不可能であった機能開発が可能になる) とのこと。要は Facebook が主導する外部プロジェクトである ReasonML に依存せずに開発を進めていくためにフォークするという話で、Chromium のレンダリングエンジンが Apple の WebKit から Google 主導の Blink に切り替わったのと似た動機である (プログラミング言語の分野でも Object Pascal が Pascal を逸脱して Delphi Language になったとか PLT Scheme (の第一言語) が RnRS とは別路線に舵を切って Racket になったとか、割とよくある話である。) 公式ブログの Q&A によると OCaml / ReasonML 文法のサポートは継続され、既存の BuckleScript プロジェクトは問題なくビルドできるとのこと。ただし現時点で公式ドキュメントは ReScript 文法のみに言及しているなど、サポート水準のティアを分けて ReScript 文法を優遇することで移行を推進していく方針である。 上流である OCaml の更新は取り込み、AST の互換性も維持される。将来 ReScript から言語機能が削除されることは有り得るが、OCaml / ReasonML からは今日の BuckleScript が提供する機能すべてにアクセスできる。 現時点における ReScript の

多分週刊チラシの裏 (Mar 23, 2021 - Mar 27, 2021)

Intel プロセッサのマイクロコードを変更する非公開命令が発見される 今日のプロセッサは複雑な命令を単純な回路で実装したりバグの修正を容易にするため、1 個の命令でも実際にはプロセッサ内部に格納されたマイクロプログラムを実行するようになっていることが多い。 かつて浮動小数点演算器のバグで Pentium をリコールする羽目になった Intel も例外ではないのだが、Intel が電子署名したマイクロコードでなくとも適用できる非公開命令が発見されたという報告。 ただし無条件ではなく、命令自体はユーザモードでもデコードされるがプロセッサが特定の “Unlocked State” にないときは未定義命令として処理されるらしい。 MSKK の週休三日トライアルで生産性が四割向上 2019 年の記事。週休三日制を導入する事業所は中小を中心に増加しているが、Microsoft の日本法人であるマイクロソフト株式会社 (MSKK) が “Work Life Choice Challenge” と称して 2019 年夏に実施した金曜日を休日とする試験的措置において、前年同月比 40 % の生産性向上が見られたとのこと。 同施策は休日の追加に加えて会議時間短縮の奨励、またメッセージングアプリによる会議自体の代替なども含んでいる。 2015 年の電通における過労自殺事件に国際的な耳目が集まって以降、日本は「過労死」に象徴される長時間労働の是正に取り組んでおり、MSKK のこの措置は将に時節を得たものであったと言える。 r/WallStreetBets からゴリラ保護基金へ多額の寄付 「みんなで株価吊り上げて食い付いたヘッジファンド釣ろうぜ」という一種の祭で GameStop の株価が高騰したのは今年の 1 月だが、その震源地であった Reddit の WallStreetBets (WSB) コミュニティからマウンテンゴリラ保護のための基金である The Dian Fossey Gorilla Fund International に 350,000 USD の寄付があったとのこと。 ところで何故ゴリラかというと「猿の惑星」に倣って WSB コミュニティ内で同志を猿 (ape) と称していたからとか。異説に「猿みたいに株を買うのにキーボードを連打しているから」とも。

OCaml で Web フロントエンドを書く

要旨 フロントエンド開発に Elm は堅くて速くてとても良いと思う。昨今の Flux 系アーキテクチャは代数的データ型と相性が良い。ところで工数を減らすためにはバックエンドも同じ言語で書いてあわよくば isomorphic にしてしまいたいところだが、Elm はバックエンドを書くには現状適していない。 OCaml なら js_of_ocaml でエコシステムを丸ごとブラウザに持って来れるのでフロントエンドもバックエンドも無理なく書けるはずである。まず The Elm Architecture を OCaml で実践できるようにするため Caelm というライブラリを書いている。俺の野望はまだまだこれからだ (未完) Elm と TEA について Elm というプログラミング言語がある。いわゆる AltJS の一つである。 ミニマリスティクな ML 系の関数言語で、型推論を持ち、型クラスを持たず、例外機構を持たず、変数の再代入を許さず、正格評価され、代数的データ型を持つ。 言語も小綺麗で良いのだが、何より付属のコアライブラリが体現する The Elm Architecture (TEA) が重要である。 TEA は端的に言えば Flux フロントエンド・アーキテクチャの変種である。同じく Flux の派生である Redux の README に TEA の影響を受けたと書いてあるので知っている人もいるだろう。 ビューなどから非同期に送信される Message (Redux だと Action) を受けて状態 (Model; Redux だと State) を更新すると、それに対応して Virtual DOM が再構築されビューがよしなに再描画され人生を書き換える者もいた——という一方向の流れはいずれにせよ同じである。 差異はオブジェクトではなく関数で構成されていることと、アプリケーション外部との入出力は非同期メッセージである Cmd / Sub を返す規約になっていることくらいだろうか。 後者は面白い特徴で、副作用のある処理はアプリケーションの外で起きて結果だけが Message として非同期に飛んでくるので、内部は純粋に保たれる。つまり Elm アプリケーションが相手にしないといけない入力は今現在のアプリケーションの完全な状態である Model と、時系列イベ

多分週刊チラシの裏 (Feb 28, 2021 - Mar 22, 2021)

JavaScript 開発者が如何にして TypeScript 嫌いから TypeScript ファンになったか 気軽な読み物。型宣言の冗長さとジェネリクスなどの複雑性を嫌って (選択肢にあれば) JavaScript の方を選んできた筆者が TypeScript しか選べない職場に移って数ヶ月後にはすっかりファンになっていたという話。 理由は月並で「『不可能な状態を不可能にする』Union Type と網羅性チェック」「コンパイル時型検査によるエラーの早期検出」「リッチな IDE 支援」の 3 本。理由がそれだけなら個人的には Flow か Elm を進めたいところではある。 NASA の最新火星ローバーが搭載するプロセッサは 1998 年の iMac と同じ NASA が Mars 2020 ミッションのために送り出し、先月火星表面に着陸した最新かつ過去最大のローバーである Perseverance の話。 2021 年に活動を開始したこのハイテク・ガジェットのメインプロセッサは PowerPC 750 であるとのこと。1998 年発売の初代 iMac が搭載していた “G3” プロセッサといえば分かり易いだろう。 もちろん民生品そのものではなく、-55 - 125 ℃ の気温と 200,000 - 1,000,000 Rad の放射線に耐える特別仕様の BAE Systems RAD750 である。ちなみに「火星で自撮り」という快挙を成し遂げたのち現在も活動中の先代 Curiosity も同じものを搭載している。動作周波数 110 - 200 MHz、価格は $200,000 程度とのこと。 Internet Archive Infrastructure 過去の Web サイト、書籍、ビデオに音楽からクラシックソフトウェアまでインターネットに公開されたあらゆるデータを収集・保存する Internet Archive のインフラ紹介ビデオ。 クラウドは一切使っておらず、自前のベアメタルサーバ 750 台に接続されたストレージはシステム全体で 200PB とのこと。保存されるデータは現在のところ年 25 % 以上増大しており、四半期で 5 - 6 PB 規模だという。 Semantic Versioning はお前を救わない 「ある API