k_oomoriこんにちは、k_oomoriです。今回は、タイトルの通りプログラミング言語Scalaについて書いてみたいと思います。Scalaの特徴を俯瞰していきましょう。・オブジェクト指向と関数型のハイブリッド言語であるScalaは、関数型言語とオブジェクト指向(命令型)言語の特徴を統合したマルチパラダイムなプログラミング言語です。どちらのスタイルを用いるかはプログラマに委ねられており、関数型言語にすでに親しんでいる人はvalやイミュータブル(不変)オブジェクトを用いて関数型の記述を行えばいいし、命令型の方が適している問題に対してはvarとミュータブル(可変)オブジェクトによる命令型の書き方ができます。型付け言語である静的な型システムを持っているため、コンパイル時(というかIDEの力を借りればコーディング時)に型に関するエラーを確実に検出できます。強力な型推論システムも併せ持っているため、至る所に型情報を書いて回ったりする手間はかかりません。・Javaと容易に連携できるScalaプログラムはコンパイルするとJVMバイトコードに変換され、JVM上で動作します。そのため、既存のJavaコードと容易に共存させることができます。実際、Scalaの文字列はScala独自のものではなく、java.lang.Stringをそのまま用いているそうです。Scala用ライブラリが提供されていなくても、Java用のライブラリがあればそれをそのまま使うことができます。Java)・Scalaの構文要素は値を返す、つまり式であるここから具体的なScalaコードを使って話を進めていきますが、Scalaの基本的な文法に関する説明はここでは省かせていただきます。そのあたりはやはりScalaの設計者であるOdersky氏(@odersky)らによる"Scalaスケーラブルプログラミング"(通称コップ本)[1]がバイブル的な位置づけになります。Scalaのインストールについては日本語情報サイトのインストールページなどを参考に、ご自身の環境に合ったものを入れてください。2.10.2で実行しています。プログラミング言語における構文要素には文(Statement)と式(Expression)があります。文は手続きを表すもので結果値を持たないのに対し、式は評価された値を持ちます。この意味において、Scalaでは定義文以外のものは全て式であるということが言えます。ifも値を返すので次のような記述が可能になります。Scalaには存在しません)。同様にforも「for文」ではなく「for式」です。このようにScalaではほとんどのものが式です。なっているかというと、それが関数型プログラミングのスタイル-引数を受け取って、結果値を返す-だからです。「Scalaの構文要素は全て式である」という特徴はScalaの関数型言語としての側面の表れであると言えます。・演算子はメソッドであり、メソッドも演算子になれるScalaにはJavaのようなプリミティブ型はなく、IntやBoolean等も含めて全てがクラスとして実装されています。これはScalaがオブジェクト指向言語で(も)あるという事実を表しています。そのため整数リテラルからも次のように直接メソッドを呼ぶことができます。*など)は全てメソッドとして実装されています。(5).+(6)、つまり5というInt型オブジェクトの+メソッドを呼び出し、引数にIntの6を与えているのです。同様に、&&も||も==も全てBool値を返すメソッドです。逆に、通常のメソッドも演算子記法で書くことが可能です。複数の引数を取る場合には括弧を省略することができません。string・いろいろな文字がメソッド名に使える上で見たように、算術演算子の正体はメソッドです。Intクラスには次のようなシグネチャのメソッドが定義されています。yのように書くことができるようになります。他にも:?~!#&などは全て演算子識別子を構成するのに有効な演算子文字です。ある問題として、与えられたURLの末尾にGETパラメータを付与する際、すでに?が含まれていれば&で、なければ?でつなぐということを誰しも一度はやったことがあると思います。ような名前を付けて定義することができます。conversion)を定義しておけば、あたかもStringのメソッドであるかのように呼び出すことができます。http://example.net/?user=hoge&foo=bar&x=1なお、通常の英数字の後に記号を付ける場合、アンダースコア(_)を挟まなければなりません。()Booleanさらに、Java同様Scalaでも識別子にUnicodeを使用できるので、メソッド名に日本語のようなマルチバイト文字を使うことも可能です。その上、「使用が可能な」だけでなく、あらかじめ用意されているマルチバイト識別子すらあるのです!それは→,⇒,←で、それぞれ->,=>,<-に対応します。従って次のようなコードも普通にコンパイラを通り、実行することができちゃいます。5.0)なお、メソッド名だけでなくクラス名、変数名にも日本語を使うことができるため、日本語によるプログラミングも可能です[3]。業務案件で積極的に使うべきか、と問われるとたぶんNoですが...。・メソッド名の末尾がコロン(:)だと...コロンも有効な演算子文字だという話をしました。演算子名の末尾がコロンだった場合、メソッド呼び出しの元となるオブジェクト(レシーバーといいます)と引数の位置が逆転します。listはlist.::(a)になるのです。ちなみに::(cons)はListクラスで定義されたメソッドで、既存リストの先頭に要素を追加した新たなリストを返します(ScalaのListはimmutable(不変)なので、操作によって元のリストが変更を受けたりはしません)。このルールが採用されたかについてはコップ本にも特に言及はなさそうなのですが、おそらく「リストの先頭に追加する感」を出したかったのではないかと推測されます。left、左畳み込み)などがあります。整数リテラル1、浮動小数点リテラル3.14F、文字リテラル'A'、文字列リテラル"scala"、論理値リテラルtrue、Nullリテラルnull、配列リテラルArray(1,2,5,3)などは特に説明不要と思いますが、Scalaには他にもいくかのリテラルが存在します。'symbシングルクォートを使うことはCharと一緒ですが、なんと閉じていない!このリテラルは、実際には以下のようなscala.Symbolのファクトリーメソッド呼び出しに展開されているそうです。'symbnameメソッドを使うとそのシンボルの名前を文字列として取り出すことができます。symbでは文字列と何が違うかというと、文字列では同じ内容でもインスタンスとしては異なる場合があるのに対し、シンボルは同じシンボルリテラルを複数書いても全く同一のSymbolオブジェクトを参照することが保証される、とのことです。trueここでeqはインスタンスとして同一かどうかを判定するメソッドで、Javaのオブジェクト型に対する==に相当します。Scalaで文字列を比較する場合は普通==で「値として」同じかどうかを判定するので、Symbolの必要にかられた経験は今のところないです...。次はXMLリテラルです。</language></languages>textメソッドでタグを取り除いたり、\\メソッド(!)で要素を抽出したり、toStringメソッドで文字列に変換したりできます。</language></languages>一つ注意しなくてはいけないのは、2つの変数の大小を比較するとき、次のように書いてはいけません。^もうお気付きのことと思いますが、aタグリテラルが開始されたまま閉じてないと認識されてエラーになっています。Scalaの関数は多くの場合決まった型の結果値を返しますが、副作用を起こすことだけが目的で特に結果値を返す必要のない関数・メソッドもあります。この場合の結果型はUnitとなり、「意味のある値を返さない」ことを意味します。Javaのvoidのようなものではありますが、値がないわけではなく、ScalaのUnit型はただ一つの値「()」を持っています。プログラム中に()と書けばそれはUnitリテラルになりますが、まず役に立つことはないでしょう。クラス階層の最下層、つまり全てのクラスのサブクラスとしてNothingクラスがあるのですが、これには本当に値がありません。他にも関数リテラルというものもあるのですが、それは次の章で説明します。strings)と呼ばれるものがあり、ダブルクォートを3個続けて(""")書きます。他の言語で言うところのヒアドキュメントみたいなものと思えばよいでしょう。この中ではダブルクォートや\などをエスケープせずにそのまま書くことができます。・Tuple22問題が存在するListやMapのようなコレクションには、特定の型の要素しか持たせることができません。1と"2"を要素に持つListを作成しようとすると、その型はList[Any]になってしまいます。2)これを元の型を維持しつつまとめて保持したいと思ったときに便利なのがタプル(Tuple)です。2),true,'xyz)これは実際のところTuple5というケースクラスのファクトリーメソッドを呼んでいることに相当しています。2.10時点では23個以上のパラメータを持つケースクラスを定義することができません。^この制限は当然タプルにも受け継がれ、Tuple23以上は存在しません。2.11ではこの数が大幅に増えるという噂も...)まあ普通はこんなに使うことはないんですが、データベースのレコードをタプルにマッピングする実装では(テーブルはカラムごとに型が異なるのが一般的なのでタプルが便利!)、カラムが23個以上あるテーブルを扱うことができなくなってしまいます。このようにTuple22までしかないことに起因する困難は「Tuple22問題」と呼ばれ、Scala界隈ではかなり有名なようです。同様に関数についても"Function22問題"が存在するのですが、23個以上の引数をフラットに持つ関数を定義しなければならない状況はあんまりなさそうなので、こちらはそれほど表面化しないような気がします。タプルから値を取り出す方法は主に2通りあります。2)前者は特に説明の必要はないと思います。後者は._NでN番目の要素にアクセスしているのですが、Nは0ではなく1スタートであることに注意してください。これはコップ本(第2版では67ページ)で解説されているように、HaskellやMLなど関数型言語の伝統を受け継いだ結果だそうです。タプルはimmutableなので、一度アサインされた要素を書き換えることはできません。値としての受け渡しなどその言語における基本的な操作ができる対象のことで、文字列や数値などはその代表的なものです。関数型言語においては関数も第一級オブジェクトとして扱えること、即ち第一級関数の存在が必要不可欠になります[4]。関数本体と定義しますが、このままではこの関数を別の関数に引数として渡したり、変数に格納したりすることはできません。呼び出しを実現できますが、動的言語ではないScalaでは引数部分にdefで定義した関数名を渡せないのです。するかというと、関数値を使います。その関数値の設計図とも言えるものが関数リテラルです。<function2>これはxとyという2つの整数引数を取り、それらの和(x+y)を返す「関数」です。値が<function2>となっているのは、Function2トレイト(引数を2個取る関数のインターフェイス的なもの)を継承したクラスのインスタンスであることを意味しています。^applyメソッドが未定義だと怒られましたので実装してみます。yは上記Function2を用いた書き方のシンタックスシュガーのようです。これは関数なので次のように適用することが可能ですが、見るからに不便です。6後者の書き方からわかるように、関数リテラルは実行時にはオブジェクトになっているため、変数に格納することが可能です。すると、自然な形で関数を呼び出すことができるようになります。values)といいます。これをどのようにして「別の関数に引数として渡す」のか、例を用いて見てみましょう。ここでは与えられたURLのリストの中から、ある条件(パターンに対して前方一致や正規表現など)に合致するものを取り出す関数を考えます。Boolean、つまり文字列型引数を2つ取って論理値を返す関数となっています。これは次のように使います。http://www.example.net/login.php)startsWithは、レシーバー文字列が引数文字列で始まっていればtrueを、そうでなければfalseを返すメソッドです。始まるものを抽出するという意味になっており、実際wwwサブドメインでないものは除かれています。functions)といいます。foo.startsWith(bar)でもなんでもいいことがわかるでしょう。