カタログ番号CJ0074-1A-2(2005年2月)より抜粋 …...カタログ番号CJ0074-1A-2(2005年2月)より抜粋 掲載内容・抜粋ページ [P225~P237] クリーンルーム対応
第一回社内 Scala 勉強会(一部抜粋)
-
Upload
lyricallogical -
Category
Technology
-
view
3.016 -
download
1
description
Transcript of 第一回社内 Scala 勉強会(一部抜粋)
Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. https://lepidum.co.jp/
Scala の言語機能
ここからが本番です
全ての言語機能について語るのは無理
本が書けるよ(多分上下巻)!
Scala で何ができるようになるか、を重点した
つもり…
Confidential
Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. https://lepidum.co.jp/
Scala の言語機能 – 型に対する制約
Java の場合
Nominal Subtyping
あるクラスと派生クラスの関係に基づく制約
Confidential
public class Duck { … } public class UglyDuck extends Duck { … } public class DuckBreeder<T extends Duck> { … }
Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. https://lepidum.co.jp/
Scala の言語機能 – 型に対する制約
Java の場合
Nominal Subtyping
あるクラスと派生クラスの関係に基づく制約
予め継承している必要がある
Confidential
public class Duck { … } public class UglyDuck extends Duck { … } public class DuckBreeder<T extends Duck> { … }
Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. https://lepidum.co.jp/
Scala の言語機能 – 型に対する制約
Scala の場合
Nominal Subtyping
勿論 Scala にもある
Confidential
class Duck { … } class UglyDuck extends Duck { … } class DuckBreeder[T <: Duck] { … }
Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. https://lepidum.co.jp/
Scala の言語機能 – 型に対する制約
Java の場合
Nominal Subtyping
あるクラスとその派生型のみを許容
予め継承している必要がある
問題点:機能を備えていても、継承していないとダメ
Confidential
public static boolean genericIsEmpty<T extends ???>(T t) { return t.isEmpty(); } // String も List も isEmpty を持ってはいるが… genericIsEmpty(“”); genericIsEmpty(new ArrayList());
Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. https://lepidum.co.jp/
Scala の言語機能 – 型に対する制約
Scala の場合
Structural Subtyping
クラスの構造に基づく制約
必要な機能を備えてさえいれば、継承関係は必要ない
Confidential
type HasIsEmpty = { def isEmpty(): Boolean } def genericIsEmpty[T <: HasIsEmpty](t: T) = t.isEmpty() genericIsEmpty(“”) genericIsEmpty(new java.util.ArrayList())
Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. https://lepidum.co.jp/
Scala の言語機能 – 型に対する制約
Scala の場合
Structural Subtyping
クラスの構造に基づく制約
必要な機能を備えてさえいれば、継承関係は必要ない
実は名前をつける必要も制約にする必要もない
Confidential
def genericIsEmpty(v: { def isEmpty(): Boolean }) = v.isEmpty() genericIsEmpty(“”) genericIsEmpty(new java.util.ArrayList())
Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. https://lepidum.co.jp/
Scala の言語機能 – 型に対する制約
Scala の場合
Structural Subtyping
クラスの構造に基づく制約
必要な機能を備えてさえいれば、継承関係は必要ない
実装にはリフレクションが使われているので注意
通常のメソッド呼び出しに比べると遙かに遅い
メソッドキャッシュもあるし、そこまで気にしなくてもいいけれど…
分割コンパイルの実現のために仕方なくこうなっている
Confidential
Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. https://lepidum.co.jp/
Scala の言語機能 – 型に対する制約
Java の場合
機能を備えていないが、定義することができる場合
問題点:制約がどうのこうの以前の問題だ…
Confidential
public static char genericHead<T extends ???>(T t) { return t.head(); } genericHead(“akari”);
Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. https://lepidum.co.jp/
Scala の言語機能 – 型に対する制約
Java の場合
機能を備えていないが、定義することができる場合
問題点:制約がどうのこうの以前の問題だ…
解決:Adapter pattern(GoF) を利用する
Confidential
public interface Headable { char head(); } public class StringHeadableAdapter implements Headable { private String str; public StringHeadable(String str) { this.str = str; } @Override public char head() { return str.charAt(0); } }
Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. https://lepidum.co.jp/
Scala の言語機能 – 型に対する制約
Java の場合
機能を備えていないが、定義することができる場合
問題点:制約がどうのこうの以前の問題だ…
解決:Adapter pattern(GoF) を利用する
問題点:一々 Adapter 通すのが面倒…
Confidential
public static char genericHead<T extends Headable>(T t) { return t.head(); } genericHead(new StringHeadableAdapter(“akari”));
Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. https://lepidum.co.jp/
Scala の言語機能 – 型に対する制約
Scala の場合
機能を備えていないが、定義することができる場合
Implicit Conversions により機能を備えた型に変換
Implicit と修飾された引数を一つ取る関数により定義
Confidential
trait Headable { def head(): Char } class StringHeadable(str: String) extends Headable { def head() = str.charAt(0) } implicit def stringIsHeadable(str: String) = new StringHeadable(str)
Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. https://lepidum.co.jp/
Scala の言語機能 – 型に対する制約
Scala の場合
機能を備えていないが、定義することができる場合
Implicit Conversions により機能を備えた型に変換
Implicit と修飾された引数を一つ取る関数により定義
View Bounds と呼ばれる型制約が利用可能
Confidential
// T から Headable へ暗黙に変換可能なことを要求 def genericHead[T <% Headable](t: T) = t.head()
Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. https://lepidum.co.jp/
Scala の言語機能 – 型に対する制約
Scala の場合
機能を備えていないが、定義することができる場合
Implicit Conversions により機能を備えた型に変換
Implicit と修飾された引数を一つ取る関数により定義
View Bounds と呼ばれる型制約が利用可能
変換は暗黙に行われる
Java の問題点を解決
明示的に変換することもできる
Confidential
genericHead(“akari”) genericHead(stringIsHeadable(“akari”)) genericHead(new StringHeadable(“akari”))
Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. https://lepidum.co.jp/
Scala の言語機能 – 型に対する制約
Pimp My Library (pattern)
Implicit Conversions による機能追加の名称
Scala 標準ライブラリでも普通に使われている
Scala の String は java.lang.String
でも何故か何もしなくても head メソッドが呼べてしまう
予めリッチな型への暗黙変換が定義されているため
他にも色々
RichXXX とか WrappedXXX とか XXXOps とか
Confidential
Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. https://lepidum.co.jp/
Scala の言語機能 – 型に対する制約
Pimp My Library と他言語の機能の比較
Ruby の Open Classes
グローバルに影響してしまう
Scala なら import によりコントロール可能
メソッドが「本当に」追加される(善し悪しは兎も角)
動的型付きなので型制約に関しては特になし
C# の Exntension Methods
単なる Syntax Sugar に過ぎない
よって、拡張したクラスが満たすことのできる制約は増えない
Confidential
Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. https://lepidum.co.jp/
Scala の言語機能 – 型に対する制約
Implicit Conversions の弱点
定義が面倒なことがある
2.10 で導入される Implicit Classes である程度解決
変換の度に中間オブジェクトが生成される
2.10 で導入される Value Classes で解決
C# の Extension Methods とほとんど同じ
暗黙に行われるため、コードが追いづらい
Eclipse, IntelliJ IDEA なら変換箇所はハイライトされる
頑張れ
Confidential
Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. https://lepidum.co.jp/
Scala の言語機能 – 型に対する制約
ちょっと戻る
Confidential
Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. https://lepidum.co.jp/
Scala の言語機能 – 型に対する制約
Java の場合
機能を備えていないが、定義することができる場合
問題点:制約がどうのこうの以前の問題だ…
解決:Adapter pattern をちょっと変形して利用
何を扱う Adapter なのかを型パラメタを取ることで分かるように
Confidential
public interface Headable<T> { char head(T t); } public class StringHeadable implements Headable<String> { @Override public char head(String str) { return str.charAt(0); } }
Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. https://lepidum.co.jp/
Scala の言語機能 – 型に対する制約
Java の場合
機能を備えていないが、定義することができる場合
問題点:制約がどうのこうの以前の問題だ…
解決:Adapter pattern をちょっと変形して利用
問題点:やっぱり面倒…
型情報から何とかして適切な Adapter を選択できないか?
Confidential
public static char genericHead<T>(T t, Headable<T> ev) { return ev.head(t); } genericHead(“akari”, new StringHeadable());
Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. https://lepidum.co.jp/
Scala の言語機能 – 型に対する制約
Scala の場合
機能を備えていないが、定義することができる場合
Implicit Patameter により機能を備えた値を要求
値は「型に基づいて」自動的に探索される(詳細は後述)
Adapter Pattern をちょっと変形したのはこれのため
Java の問題点解決!
Confidential
def genericHead[T](T t)(implicit ev: Headable[T]) = { ev.head(t) } genericHead(“akari”) // ev は適切な値が見つかれば自動的に渡される
Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. https://lepidum.co.jp/
Scala の言語機能 – 型に対する制約
Scala の場合
機能を備えていないが、定義することができる場合
Implicit Patameter により機能を備えた値を要求
Context Bounds と呼ばれる型制約も利用可能
直接は使わないが、必要とするメソッドを呼ぶとき等に
Confidential
// Headable[T] が暗黙に定義されていることを要求 def genericHeadAsString[T : Headable](T t) = { genericHead(t).toString }
Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. https://lepidum.co.jp/
Scala の言語機能 – 型に対する制約
Scala の場合
機能を備えていないが、定義することができる場合
Implicit Patameter により機能を備えた値を要求
implicit と修飾された val, var, def, object が対象
var はやめておきましょうね…
Confidential
trait Headable[T] { def head(t: T): Char } implicit object stringHeadable extends Headable[String] { def head(str: String) = str.charAt(0) }
Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. https://lepidum.co.jp/
Scala の言語機能 – 型に対する制約
Scala の Implicit Parameters
引数の候補はどこから選ばれる?
メソッドの利用箇所から見える定義群と(自明)
要求されている型のコンパニオンオブジェクト内から
複数見つかった場合は?
最も定義場所の近い物が優先される
同じ名前空間で複数見つかった場合はエラー
Confidential
Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. https://lepidum.co.jp/
Scala の言語機能 – 型に対する制約
コンパニオンオブジェクトとは?
クラスと同名のオブジェクト
User オブジェクトはコンパニオンオブジェクト
ここではこれ以上は触れません
Confidential
class User(name: String, age: Int) object User { … }
Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. https://lepidum.co.jp/
Scala の言語機能 – 型に対する制約
_人人人人人人人人人人_
> 突然の Type Classes <
 ̄Y^Y^Y^Y^Y^Y^Y^Y ̄
Confidential
Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. https://lepidum.co.jp/
Scala の言語機能 – 型に対する制約
Scala の Implicit Parameters
実は Type Classes を実現するための言語機能
これまでのコードは下の Haskell コードと完全に一致
完全に一致、分かりましたですね?
Confidential
class Headable a where head :: a -> Char instance Headable String where head str = str !! 0 headAsString :: Headable a => a -> String headAsString a = show (head a)
Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. https://lepidum.co.jp/
Scala の言語機能 – 型に対する制約
Type Classes
Functor, Applicative, Monad …
じゃない!!
モナモナするためだけのものではない
Type Classes = 型に機能を外から与える仕組み
あれ…なんだかデジャブ?
Implicit Conversions と Implicit Parameters って似てる?
実は Implicit Conversions も似たような物
手前味噌ですが参考
より詳細な話は今回はしません
Confidential
Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. https://lepidum.co.jp/
Scala の言語機能 – 型に対する制約
標準ライブラリにおける Type Classes の実例
scala.reflect.ClassManifest
ClassManifest[T] は T の型情報を扱う
配列の生成時によく使われる
scala.collection.generic.CanBuildFrom
CanBuildFrom[From, Elem, To] 三つも型パラメタが!
From というコレクションから
Elem を要素とする
To というコレクションを生成する
ための Builder[Elem, To] を提供する
Confidential
Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. https://lepidum.co.jp/
Scala の言語機能 – 型に対する制約
Implicit Parameters のその他の用法
Type Classes と全く関係ない利用法も
Fighting type erasure(pdf 注意、スライドです)
何らかのコンテキストを引き回す
android.os.Context の引き回し
弊社のアンドロイドアプリのコードでも使われている
play.api.Application の引き回し
弊社の API サーバーのコードでも使われている
play.api.db.Connection の引き回し
弊社の API サーバーのコードでも使われて…なかった
Confidential
Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. https://lepidum.co.jp/
Scala の言語機能 – 型に対する制約
まとめ 1
Structural Subtyping
継承関係ではなく構造に基づいた制約が可能
Implicit Conversions(View Bounds)
暗黙に変換可能かどうかに基づいた制約が可能
実は Implicit Parameters と大差ない
Implicit Parameters(Context Bounds)
暗黙に定義されているかどうかに基づいた制約が可能
実は Type Classes が実現可能
Confidential
Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. https://lepidum.co.jp/
Scala の言語機能 – 型に対する制約
まとめ 2
Scala では様々な種類の型に対する制約がある
制約の種類が多い=柔軟に抽象的な設計が可能
アブストラクションヤッター!
触れなかったこと
Variance
Type constructor parameters
Lower bounds
これはまあ Java にもあるしね…
forSome
Confidential