書いて覚えるSwift入門

第3回 演算子

この記事を読むのに必要な時間:およそ 3 分

オレオレ演算子の書き方

ここまでは,既存の演算子をユーザが定義した型に適用していました。いわゆる演算子オーバーロードで,ここまでであればできる言語は少なくありません。しかしここから先はSwiftのほかにはHaskellぐらいしかできない領域,オレオレ演算子の世界です。

たとえばこんなのはいかがでしょう?

infix operator => { associativity left precedence 95 }
    func => <A,R> (lhs:A, rhs:A->R)->R {
    return rhs(lhs)
}

f(a)の代わりに,a => fと書けるようになります。

これの何がうれしいかというと,たとえばprintfデバッグならぬprintlnデバッグの時。Swiftにはplaygroundがあるのでprintlnデバッグしなければならないケースは他より減るとはいえ,コマンドラインでのテストなどにやはり重宝します。こういう時にわざわざprintln(と書いて)で閉じるより,そのままうしろに=> printlnと付け加えた方が楽ですし直感的でもあります。

見てのとおり,ユーザが演算子を定義する際には,(pre¦in¦post)fix operatorで演算子を定義しておく必要があります。続く{}の中で,結合の方向と優先順位を定義します。ここでは左結合,優先順位95なので,=>の重ね打ちも図3のような感じでできたりします。

図3 オレオレ演算子の実行結果

図3 オレオレ演算子の実行結果

演算子に関しては,⁠こんなのどうよ」というのをGitHubにまとめてあるのでよろしければご確認を。

The (Un)?documented Feature

それではどのような記号が演算子として使えるのか。公式ドキュメントにはこう書いてあります図4⁠。

図4 公式ドキュメントでのU+の羅列?

図4 公式ドキュメントでのU+の羅列?

U+の羅列,なんのこっちゃという感じですが,これ,Unicodeの記号文字です。ということは……,リスト1のコードが動くということではありませんか? playgroundで実行してみてください図5⁠。

リスト1 公然の秘密のサンプルコード

import Foundation
prefix operator √ {}
prefix func √(x:Double)->Double {
    return sqrt(x)
}
√2
// U+2211, N-ARY SUMMATION
// not U+3A3, GREEK CAPITAL LETTER SIGMA
infix operator Σ { }
func Σ (r:Range<Int>, f:Double->Double)->Double {
    return Array(r).map{f(Double($0))}.reduce(0,+)
}
let s = 1...10 Σ {$0}
s
// U+220F, N-ARY PRODUCT
// not U+3A0, GREEK CAPITAL LETTER PI
infix operator Π { }
func Π (r:Range<Int>, f:Double->Double)->Double {
    return Array(r).map{f(Double($0))}.reduce(1,*)
}
let p = 1...10 Π {$0}
p

図5 リスト1の実行

図5 リスト1の実行

1つ注意したいのは,使えるのはあくまで記号であって,ギリシャ文字などは記号ではなく普通の文字として扱われること。図5のΣはU+3A3(GREEK CAPITAL LETTER SIGMA)ではなくU+2211(N-ARY SUMMATION⁠⁠,ΠもU+3A0(GREEK CAPITAL LETTER PI)ではなくU+220F(N-ARY PRODUCT)です。

記号が使えることはかつては公然の秘密でしたが,Swift 1.1現在では公式化されています。

さらに次のコードを追記してみてください。

for n in 1...16 {
    let e_1 = 1...n Σ {1/(1...Int($0) Π {$0})}
    println( exp(1) - e_1 )
}

どんどん1に近づいています。どこかで見たことがありませんか? そう,ネイピア数,eの定義です。

指数関数exp(x)はテイラー展開で

画像

と書けますが,1...n Σ {1/(1...Int($0) Π {$0})}exp(1) - 1に相当するわけです。なぜexp(1)そのものではないかというと,階乗計算に使っているΠは,上の定義では0!が扱えないから。第0項がない分,1少ないわけです。

ここまでくるといっそ後置の!を定義してn!とかやりたい誘惑に駆られますが,残念ながらn!はImplicitly Unwrapped Optionalsのために予約されていて再定義不可能です。

まとめ

Lispを見ればわかるとおり,演算子というのはプログラミング言語に必須の機能ではありません。が,やはりLispを見ればわかるとおり,演算子というのは一定以上の人気を得るのに欠かせない機能でもあるようです。この点において,Swiftに比肩するのはHaskellぐらいしか見当たりません。

そして一定以上の人気を得るのに欠かせないいまひとつの機能が,過去の遺産の継承。次回はSwiftからCやObjective-Cの遺産を活用します。

Software Design

本誌最新号をチェック!
Software Design 2019年12月号

2019年11月18日発売
B5判/200ページ
定価(本体1,220円+税)

  • 第1特集
    サーバーレスでめざせ! インフラ管理ゼロなシステム
    基本のAWS Lambdaからフルサーバーレスまで
  • 第2特集
    12月6日発売『みんなのPHP』コラボ!
    PHPプログラミング・アラカルト
    なぜ愛され,なぜ進化するのか?
  • 短期連載
    Webサービスを裏で支える!! バッチ処理設計の勘所
    【1】バッチ処理の特徴と設計のポイント
  • 短期集中連載
    Webエンジニアのための時短スマホアプリ開発
    【2】React.jsをおさらいし,React NativeによるUI構築の基本を知ろう

著者プロフィール

小飼弾(こがいだん)

1969年生まれ,東京都出身。元ライブドア取締役の肩書きよりも,最近はPokemon GOのガチトレーナーのほうが有名になりつつある……かもしれない永遠のエンジニアオヤジ。

活躍の場はIT業界だけでなく,サブカルからアカデミックまで多方面にわたり,ネットからの情報発信は気の向くまま毎日毎秒! https://twitter.com/dankogai,ニコニコチャンネルは,http://ch.nicovideo.jp/dankogai,blogはhttp://blog.livedoor.jp/dankogai/

当社刊行書籍は『小飼弾のアルファギークに逢ってきた』『小飼弾のコードなエッセイ』など。他にも著書多数。