Scalaでは基本的に演算子ってものがないっぽい。
+とか.とか全部クラスのメソッド。
なのでいろいろフリーダムな感じでメソッド名を定義できる。

class Polygamist(var firstName:String, var lastName:String){
var spouses:List[ScalaPerson] = Nil

def <+(s:ScalaPerson) = {
this.spouses = s :: this.spouses
}
}

前回やったScalaPersonと似ているけど、今度は配偶者(ScalaPerson)をたくさん持てるPolygamist。

んで<+メソッドで配偶者を追加。ひでえなw
ちょっと動かしてみよう。
object TestMain{
def main(args:Array[String]){
val p = new Polygamist("美香", "叶")
p <+ new ScalaPerson("六郎", "岡島")
p <+ new ScalaPerson("ひろし","中村")
p <+ new ScalaPerson("拓哉","木村")
p <+ new ScalaPerson("龍馬", "坂本")

p.spouses.map(println)
}
}

んで実行結果は↓
性:坂本,名:龍馬
性:木村,名:拓哉
性:中村,名:ひろし
性:岡島,名:六郎

なんか組み込みの演算子にしか見えんね。

と、ここまできて感のいい人は気づく。自分は気づかなかった。
scala> val list = List("foo","bar","hoge")
list: List[java.lang.String] = List(foo, bar, hoge)

scala> list(2)
res27: java.lang.String = hoge

この(2)ってのも実はメソッド。applyメソッドっていうらしい。
さっきのPolygamistに、「x番目の旦那」を返すapplyメソッドをつけてみよう。
class Polygamist(var firstName:String, var lastName:String){
var spouses:List[ScalaPerson] = Nil

def <+(s:ScalaPerson) = {
this.spouses = s :: this.spouses
}

def apply(i:Int) = this.spouses(i)
}

object TestMain{
def main(args:Array[String]){
val p = new Polygamist("美香", "叶")
p <+ new ScalaPerson("六郎", "岡島")
p <+ new ScalaPerson("ひろし","中村")
p <+ new ScalaPerson("拓哉","木村")
p <+ new ScalaPerson("龍馬", "坂本")

println("2番目の男は" + p(2))
}
}

実行するとこうなる。
2番目の男は性:中村,名:ひろし

DSLとか作り放題だなーこれ
まあ普通に使う分にはなにがメリットかっていうと、関数として動作するオブジェクトを簡単に作ることができる。そういう関数として動作するオブジェクトのことを、ファンクターっていうらしい。
すごいね。夢が広がるね。
AD

[Scala] ScalaでBeanをつくってみる

テーマ:
ScalaでBeanを作ってみよう。

http://itpro.nikkeibp.co.jp/article/COLUMN/20080820/313059/?ST=develop
にあったPersonクラスがちょうど良さげなのでパクる。

まずはJavaBeanの場合。
public class JavaPerson {
private String firstName;
private String lastName;
private JavaPerson spouse;

public JavaPerson( String firstName,
String lastName,
JavaPerson spouse ){

this.firstName = firstName;
this.lastName = lastName;
this.spouse = spouse;
}

public JavaPerson( String firstName,
String lastName ){

this(firstName, lastName, null);
}

public String getFirstName() {
return firstName;
}

public void setFirstName(String firstName) {
this.firstName = firstName;
}

public String getLastName() {
return lastName;
}

public void setLastName(String lastName) {
this.lastName = lastName;
}

public JavaPerson getSpouse() {
return spouse;
}

public void setSpouse(JavaPerson spouse) {
this.spouse = spouse;
}
}

うわなげえキモイ。
Scalaで書くとこう。
class ScalaPerson(fn:String,ln:String,sp:ScalaPerson){
var firstName = fn
var lastName = ln
var spouse = sp

def this(fn:String, ln:String) =this (fn, ln, null)
}

うーんシンプル。

まずScalaではクラス名に続けて引数を書くみたいにコンストラクタを書ける。
コンストラクタの引数はレキシカル変数としてval宣言される。
なので外部からはアクセスできないけれど、クラス内からはそのままアクセスできる。
変更できないけど。

そしてインスタンス変数はデフォルトpublicな扱い。
なのでアクセッサーないけど直接.firstName =~みたいにアクセスする。
というかこれをアクセッサーと考えてよいみたい。

あとコンストラクタのオーバーロードはthis関数を定義してやる。

ちなみにこういうBean的なクラスであれば、コンストラクタ引数そのままクラスメンバでよくね?
ってなる。そしてそういう書き方ができる。
class ScalaPerson( var firstName:String,
var lastName:String,
var spouse:ScalaPerson ){

def this(firstName:String, lastName:String) = {
this(firstName:String, lastName:String, null)
}
}

いいねえ。
実際に使ってみる。
object TestMain{
def main(args:Array[String]){
val p = new ScalaPerson("六郎", "岡島")
println(p.firstName)
p.firstName = "八郎"
println(p firstName)
}
}

インスタンスをval宣言しているけど、内部メンバのfirstName自体はvar変数なので値を変更できている。
このへんが手続き型っぽいところ。
あと、二回目のprintlnでは.を省略して呼び出してみた。

Beanといえばそのまんまだとprintlnしても中身がわからないので
Java屋さんならtoStringしたくなるところ。

JavaでいうObjectに対応する、Scalaでのすべてのクラスの基底クラスとしてAnyクラスってのがあるらしい。これまたtoStringを持っているので、Javaのときと同じようにtoStringをオーバーライドしてやればよい。
class ScalaPerson( var firstName:String,
var lastName:String,
var spouse:ScalaPerson ){

def this(firstName:String, lastName:String) = {
this(firstName:String, lastName:String, null)
}

override def toString = {
val s = () => spouse match {
case null => ",配偶者なし"
case _ => ",配偶者:" + spouse.toString
}
"性:" + lastName + ",名:" + firstName + s()
}
}

Scalaでオーバーライドしたいときは、アノテーションとかそういう生易しいものではなく
overrideって修飾子をつけなきゃならないんだって。やりましたね!
AD

[Scala] 再帰

テーマ:
関数型の醍醐味は再帰ときいてやってきました。

ということで書いてみる。

scala> def foo(l:List[Int]):List[Int] = {
| if(l.isEmpty) Nil
| else l.head * 10 :: foo(l.tail)
| }
foo: (List[Int])List[Int]

scala> foo(List(1,2,3,4,5))
res22: List[Int] = List(10, 20, 30, 40, 50)


補足すると、isEmptyはリストが空かどうか判別する関数で、headはリストの先頭の要素を、tailは先頭から二番目以降のサブリストを取り出す関数。前にもやったけど、Nilが返る=空のリストが返る。

というかここにきて::が活きてきますなー
add的なものがないのに::があるってなんだ?って思ったけどフラグだったわけですね。はい。
Javaだとこうはいかねーなー

当然だけど各要素に適用する処理を関数として渡せる。
scala> def foo(l:List[Int])(f:(Int) => Int):List[Int] = {
| if(l.isEmpty) Nil
| else f(l.head) :: foo(l.tail)(f)
| }
foo: (List[Int])((Int) => Int)List[Int]

scala> val bar = (x:Int) => x + 5
bar: (Int) => Int = <function>

scala> foo(List(1,2,3,4,5))(bar)
res23: List[Int] = List(6, 7, 8, 9, 10)

ちなみにリストの操作をするときこんなifとか使ってるのはスマートじゃないっぽい。
どうするかというと、パターンマッチを使う。
scala> def foo(l:List[Int])(f:(Int) => Int):List[Int] = l match {
| case Nil => l
| case x::xs => f(x)::foo(xs)(f)
| }
foo: (List[Int])((Int) => Int)List[Int]

scala> foo(List(2,4,6,8,10))(bar)
res24: List[Int] = List(7, 9, 11, 13, 15)

x::xsみたいな感じでcaseを定義できるのか。これどういう動きしてるのかよくわからん。。。
これ便利だなーって思ったけどそれをそもそも用意しちゃったのがmapメソッドとかってことか。

つか関数とかメソッドとかまだあれなんだがどう使い分ければいいんだ。
AD