SlideShare une entreprise Scribd logo
1  sur  51
Télécharger pour lire hors ligne
2014.6.25    第8回  Functional  忍者
⼊入⼀一  前⽥田康⾏行行  (@maeda_̲)
Scalaの
オブジェクト
の話
⾃自⼰己紹介
前⽥田康⾏行行  ( twitter : @maeda_ )
名古屋在住  フリーランス
屋号:⼊入⼀一 ( http://www.illi-ichi.com )
はじめに
•  Scalaはオブジェクト指向⾔言語
–  既存資産を活かせるし、既存プログラマも分かりやすい
–  強⼒力力なモジュールシステム
今回のテーマ
Scalaの関数型プログラミングの中で
オブジェクトをどのように使うのか?
注意
•  この資料料では
–  Scalaでは関数とメソッドは少し違うけど、区別せずに
関数という
–  関数型⾔言語  = 静的型付け関数型⾔言語
Scalaでの
オブジェクトの⽴立立ち位置
関数型⾔言語との対応
Scala は
1. 関数型⾔言語のパーツをJavaのパーツにマッピングして
2. 使いやすいようにシンタックスなどを整えた⾔言語
パーツ ML Scala
関数 関数 メソッド
関数オブジェクト
代数データ型 ヴァリアント
レコード
case class
case object
モジュールシステム モジュール
ファンクタ
object
class
※ Haskellは型クラスによりMLのモジュールシステムと同等の機能を実現可能
(参考)
    ML Modules and Haskell Type Classes: A Constructive Comparison
http://www.cse.unsw.edu.au/~chak/papers/modules-classes.pdf
関数型⾔言語との対応
Scala は
1. 関数型⾔言語のパーツをJavaのパーツにマッピングして
2. 使いやすいようにシンタックスなどを整えた⾔言語
パーツ ML Scala
関数 関数 メソッド
関数オブジェクト
代数データ型 ヴァリアント
レコード
case class
case object
モジュールシステム モジュール
ファンクタ
object
class
※ Haskellは型クラスによりMLのモジュールシステムと同等の機能を実現可能
(参考)
    ML Modules and Haskell Type Classes: A Constructive Comparison
http://www.cse.unsw.edu.au/~chak/papers/modules-classes.pdf
モジュールとは
この資料料において、モジュールとは
ある機能についての型、値 / 関数
をまとめたもの
オブジェクトを作る
•  objectキーワードにより
シングルトンオブジェクト  (= モジュール)
が作れる
•  内部的には下記のようなイメージ
object	
  Hoge	
  {	
  
	
  	
  def	
  foo(...)	
  =	
  ...	
  
}	
  
	
  
Hoge.foo(...)	
  	
  	
  	
  	
  	
  	
  //	
  Hogeというモジュールのfooという関数を呼び出し	
  
class	
  HogeClass(){	
  
	
  	
  def	
  foo(...)	
  =	
  ...	
  
}	
  
val	
  Hoge	
  =	
  new	
  HogeClass()	
  
クラスとは?
•  パラメータ付きのモジュール
•  パラメータを渡してインスタンス化
→ モジュールができる
class	
  Hoge(connectionString:	
  String){	
  
	
  	
  def	
  foo(...)	
  =	
  ...	
  
}	
  
	
  
//	
  パラメータを渡して、モジュールの⽣生成	
  
val	
  hoge	
  =	
  new	
  Hoge("jdbc:h2:mem:test")	
  
hoge.foo(...)	
  
オブジェクトがモジュールなので
•  変数に代⼊入したり、関数に渡したり
•  package名と同様にimportもできる
class	
  Hoge(fuga:	
  Fuga){	
  
	
  	
  import	
  fuga._
    ...	
  
}	
  
Scalaのimportはどこでも書けるし、
スコープもある
コンパニオンオブジェクト
•  クラス名と同名のシングルトンオブジェクトは、
そのクラスのコンパニオンオブジェクトとなる。
•  コンパニオンオブジェクトにはそのクラスのヘルパー
関数を置く(Javaでいうstaticメソッド的なもの)
•  コンストラクタにはクラス内で使うパラメータを渡す。
(下記のコード参照)
//	
  privateをつけるとコンパニオンオブジェクトからしか⽣生成できない	
  
class	
  Hoge	
  private	
  (...){	
  ...	
  }	
  
	
  
object	
  Hoge	
  {	
  
	
  	
  //	
  引数を加⼯工して、Hogeのインスタンスを⽣生成する関数	
  
	
  	
  def	
  fromString(str:	
  String):	
  Hoge	
  =	
  new	
  Hoge(...)	
  
	
  	
  def	
  fromFile(file:	
  File):	
  Hoge	
  =	
  new	
  Hoge(...)	
  
}	
  
※ コンパニオンオブジェクトは対応するクラスと同じファイル内に記述すること
※ REPL上で試す場合は:pasteを使って⼊入⼒力力する
具体例例を⾒見見る
お題
•  ⽂文字列列とそれに対応する動作を定義したマップが
ある
•  ⽂文字列列をパースして、マップのキーのうち、どれ
をどこまで⼊入⼒力力したかを返す関数を作る
val	
  menu:	
  Map[String,	
  Action]	
  =	
  Map(	
  
	
  	
  	
  	
  "hungry"	
  -­‐>	
  GoTo("restaurant"),	
  
	
  	
  	
  	
  "tired"	
  -­‐>	
  Sleep,	
  
	
  	
  	
  	
  ...	
  
)	
  
	
  
Parser.parse("")	
  	
  	
  	
  	
  	
  	
  //	
  →	
  NoInput	
  
Parser.parse("hun")	
  	
  	
  	
  //	
  →	
  Entering(GoTo("restaurant"),	
  3)	
  
Parser.parse("hunt")	
  	
  	
  //	
  →	
  WrongInput	
  
Parser.parse("hungry")	
  //	
  →	
  Completed(GoTo("restaurant"))	
  
 
	
  
object	
  Parser	
  {	
  
	
  	
  sealed	
  abstract	
  class	
  Action	
  
	
  	
  case	
  class	
  	
  GoTo(place:	
  String)	
  extends	
  Action	
  
	
  	
  case	
  object	
  Sleep	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  extends	
  Action	
  
	
  
	
  	
  sealed	
  abstract	
  class	
  State	
  
	
  	
  case	
  object	
  NoInput	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  extends	
  State	
  
	
  	
  case	
  class	
  Entering(action:	
  Action,	
  count:	
  Int)	
  	
  	
  	
  	
  	
  	
  extends	
  State	
  
	
  	
  case	
  class	
  Completed(action:	
  Action)	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  extends	
  State	
  
	
  	
  case	
  object	
  WrongInput	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  extends	
  State	
  
	
  
	
  	
  val	
  menu:	
  Map[String,	
  Action]	
  =	
  	
  
	
  	
  	
  	
  Map("hungry"	
  -­‐>	
  GoTo("restaurant"),	
  "tired"	
  -­‐>	
  Sleep,	
  ...)	
  
	
  
	
  	
  def	
  parse(String	
  input):	
  State	
  =	
  ...	
  
	
  	
  def	
  maxMenuLength:	
  Int	
  =	
  ...	
  
}	
  
	
  
Parser.parse("hun")	
  	
  //	
  →	
  Parser.Entering(Parser.GoTo("restaurant"),	
  3)	
  
Parser.parse("hunt")	
  //	
  →	
  Parser.WrongInput	
  
#1 objectでモジュールを作る
 
	
  
object	
  Parser	
  {	
  
	
  	
  sealed	
  abstract	
  class	
  Action	
  
	
  	
  case	
  class	
  	
  GoTo(place:	
  String)	
  extends	
  Action	
  
	
  	
  case	
  object	
  Sleep	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  extends	
  Action	
  
	
  
	
  	
  sealed	
  abstract	
  class	
  State	
  
	
  	
  case	
  object	
  NoInput	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  extends	
  State	
  
	
  	
  case	
  class	
  Entering(action:	
  Action,	
  count:	
  Int)	
  	
  	
  	
  	
  	
  	
  extends	
  State	
  
	
  	
  case	
  class	
  Completed(action:	
  Action)	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  extends	
  State	
  
	
  	
  case	
  object	
  WrongInput	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  extends	
  State	
  
	
  
	
  	
  val	
  menu:	
  Map[String,	
  Action]	
  =	
  	
  
	
  	
  	
  	
  Map("hungry"	
  -­‐>	
  GoTo("restaurant"),	
  "tired"	
  -­‐>	
  Sleep,	
  ...)	
  
	
  
	
  	
  def	
  parse(String	
  input):	
  State	
  =	
  ...	
  
	
  	
  def	
  maxMenuLength:	
  Int	
  =	
  ...	
  
}	
  
	
  
Parser.parse("hun")	
  	
  //	
  →	
  Parser.Entering(Parser.GoTo("restaurant"),	
  3)	
  
Parser.parse("hunt")	
  //	
  →	
  Parser.WrongInput	
  
Parser モジュールの関数を呼び出す
Parser モジュールを作って
#1 objectでモジュールを作る
 
	
  
object	
  Parser	
  {	
  
	
  	
  sealed	
  abstract	
  class	
  Action	
  
	
  	
  case	
  class	
  	
  GoTo(place:	
  String)	
  extends	
  Action	
  
	
  	
  case	
  object	
  Sleep	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  extends	
  Action	
  
	
  
	
  	
  sealed	
  abstract	
  class	
  State	
  
	
  	
  case	
  object	
  NoInput	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  extends	
  State	
  
	
  	
  case	
  class	
  Entering(action:	
  Action,	
  count:	
  Int)	
  	
  	
  	
  	
  	
  	
  extends	
  State	
  
	
  	
  case	
  class	
  Completed(action:	
  Action)	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  extends	
  State	
  
	
  	
  case	
  object	
  WrongInput	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  extends	
  State	
  
	
  
	
  	
  val	
  menu:	
  Map[String,	
  Action]	
  =	
  	
  
	
  	
  	
  	
  Map("hungry"	
  -­‐>	
  GoTo("restaurant"),	
  "tired"	
  -­‐>	
  Sleep,	
  ...)	
  
	
  
	
  	
  def	
  parse(String	
  input):	
  State	
  =	
  ...	
  
	
  	
  def	
  maxMenuLength:	
  Int	
  =	
  ...	
  
}	
  
	
  
Parser.parse("hun")	
  	
  //	
  →	
  Parser.Entering(Parser.GoTo("restaurant"),	
  3)	
  
Parser.parse("hunt")	
  //	
  →	
  Parser.WrongInput	
  
代数データ型の定義
#1 objectでモジュールを作る
 
	
  
object	
  Parser	
  {	
  
	
  	
  sealed	
  abstract	
  class	
  Action	
  
	
  	
  case	
  class	
  	
  GoTo(place:	
  String)	
  extends	
  Action	
  
	
  	
  case	
  object	
  Sleep	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  extends	
  Action	
  
	
  
	
  	
  sealed	
  abstract	
  class	
  State	
  
	
  	
  case	
  object	
  NoInput	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  extends	
  State	
  
	
  	
  case	
  class	
  Entering(action:	
  Action,	
  count:	
  Int)	
  	
  	
  	
  	
  	
  	
  extends	
  State	
  
	
  	
  case	
  class	
  Completed(action:	
  Action)	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  extends	
  State	
  
	
  	
  case	
  object	
  WrongInput	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  extends	
  State	
  
	
  
	
  	
  val	
  menu:	
  Map[String,	
  Action]	
  =	
  	
  
	
  	
  	
  	
  Map("hungry"	
  -­‐>	
  GoTo("restaurant"),	
  "tired"	
  -­‐>	
  Sleep,	
  ...)	
  
	
  
	
  	
  def	
  parse(String	
  input):	
  State	
  =	
  ...	
  
	
  	
  def	
  maxMenuLength:	
  Int	
  =	
  ...	
  
}	
  
	
  
Parser.parse("hun")	
  	
  //	
  →	
  Parser.Entering(Parser.GoTo("restaurant"),	
  3)	
  
Parser.parse("hunt")	
  //	
  →	
  Parser.WrongInput	
  
⽂文字列列と動作の対応を
記述するマップ
#1 objectでモジュールを作る
関数の定義
 
	
  
object	
  Parser	
  {	
  
	
  	
  sealed	
  abstract	
  class	
  Action	
  
	
  	
  case	
  class	
  	
  GoTo(place:	
  String)	
  extends	
  Action	
  
	
  	
  case	
  object	
  Sleep	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  extends	
  Action	
  
	
  
	
  	
  sealed	
  abstract	
  class	
  State	
  
	
  	
  case	
  object	
  NoInput	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  extends	
  State	
  
	
  	
  case	
  class	
  Entering(action:	
  Action,	
  count:	
  Int)	
  	
  	
  	
  	
  	
  	
  extends	
  State	
  
	
  	
  case	
  class	
  Completed(action:	
  Action)	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  extends	
  State	
  
	
  	
  case	
  object	
  WrongInput	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  extends	
  State	
  
	
  
	
  	
  val	
  menu:	
  Map[String,	
  Action]	
  =	
  	
  
	
  	
  	
  	
  Map("hungry"	
  -­‐>	
  GoTo("restaurant"),	
  "tired"	
  -­‐>	
  Sleep,	
  ...)	
  
	
  
	
  	
  def	
  parse(String	
  input):	
  State	
  =	
  ...	
  
	
  	
  def	
  maxMenuLength:	
  Int	
  =	
  ...	
  
}	
  
	
  
Parser.parse("hun")	
  	
  //	
  →	
  Parser.Entering(Parser.GoTo("restaurant"),	
  3)	
  
Parser.parse("hunt")	
  //	
  →	
  Parser.WrongInput	
  
#1 objectでモジュールを作る
メニューを外部から
注⼊入したい
 
	
  
	
  
sealed	
  abstract	
  class	
  Action	
  
case	
  class	
  	
  GoTo(place:	
  String)	
  extends	
  Action	
  
case	
  object	
  Sleep	
  extends	
  Action	
  
	
  
class	
  Parser(menu:	
  Map[String,	
  Action])	
  {	
  
	
  	
  sealed	
  abstract	
  class	
  State	
  
	
  	
  case	
  object	
  NoInput	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  extends	
  State	
  
	
  	
  case	
  class	
  Entering(action:	
  Action,	
  count:	
  Int)	
  	
  	
  	
  	
  	
  	
  extends	
  State	
  
	
  	
  case	
  class	
  Completed(action:	
  Action)	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  extends	
  State	
  
	
  	
  case	
  object	
  WrongInput	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  extends	
  State	
  
	
  
	
  	
  def	
  parse(String	
  input):	
  State	
  =	
  ...	
  
	
  	
  def	
  maxMenuLength:	
  Int	
  =	
  ...	
  
}	
  
	
  
val	
  parser	
  =	
  new	
  Parser(	
  
	
  	
  Map("hungry"	
  -­‐>	
  GoTo("restaurant"),	
  "tired"	
  -­‐>	
  Sleep,	
  ...))	
  
	
  
parser.parse("hun")	
  	
  	
  	
  //	
  →	
  parser.Entering(GoTo("restaurant"),	
  3)	
  
parser.parse("hunt")	
  	
  	
  //	
  →	
  parser.WrongInput	
  
	
  
#2 メニューをパラメータとして渡す
 
	
  
	
  
sealed	
  abstract	
  class	
  Action	
  
case	
  class	
  	
  GoTo(place:	
  String)	
  extends	
  Action	
  
case	
  object	
  Sleep	
  extends	
  Action	
  
	
  
class	
  Parser(menu:	
  Map[String,	
  Action])	
  {	
  
	
  	
  sealed	
  abstract	
  class	
  State	
  
	
  	
  case	
  object	
  NoInput	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  extends	
  State	
  
	
  	
  case	
  class	
  Entering(action:	
  Action,	
  count:	
  Int)	
  	
  	
  	
  	
  	
  	
  extends	
  State	
  
	
  	
  case	
  class	
  Completed(action:	
  Action)	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  extends	
  State	
  
	
  	
  case	
  object	
  WrongInput	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  extends	
  State	
  
	
  
	
  	
  def	
  parse(String	
  input):	
  State	
  =	
  ...	
  
	
  	
  def	
  maxMenuLength:	
  Int	
  =	
  ...	
  
}	
  
	
  
val	
  parser	
  =	
  new	
  Parser(	
  
	
  	
  Map("hungry"	
  -­‐>	
  GoTo("restaurant"),	
  "tired"	
  -­‐>	
  Sleep,	
  ...))	
  
	
  
parser.parse("hun")	
  	
  	
  	
  //	
  →	
  parser.Entering(GoTo("restaurant"),	
  3)	
  
parser.parse("hunt")	
  	
  	
  //	
  →	
  parser.WrongInput	
  
	
  
#2 メニューをパラメータとして渡す
classにして外からメニュー
を渡せるように
インスタンス化して
モジュールを⽣生成
 
	
  
	
  
sealed	
  abstract	
  class	
  Action	
  
case	
  class	
  	
  GoTo(place:	
  String)	
  extends	
  Action	
  
case	
  object	
  Sleep	
  extends	
  Action	
  
	
  
class	
  Parser(menu:	
  Map[String,	
  Action])	
  {	
  
	
  	
  sealed	
  abstract	
  class	
  State	
  
	
  	
  case	
  object	
  NoInput	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  extends	
  State	
  
	
  	
  case	
  class	
  Entering(action:	
  Action,	
  count:	
  Int)	
  	
  	
  	
  	
  	
  	
  extends	
  State	
  
	
  	
  case	
  class	
  Completed(action:	
  Action)	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  extends	
  State	
  
	
  	
  case	
  object	
  WrongInput	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  extends	
  State	
  
	
  
	
  	
  def	
  parse(String	
  input):	
  State	
  =	
  ...	
  
	
  	
  def	
  maxMenuLength:	
  Int	
  =	
  ...	
  
}	
  
	
  
val	
  parser	
  =	
  new	
  Parser(	
  
	
  	
  Map("hungry"	
  -­‐>	
  GoTo("restaurant"),	
  "tired"	
  -­‐>	
  Sleep,	
  ...))	
  
	
  
parser.parse("hun")	
  	
  	
  	
  //	
  →	
  parser.Entering(GoTo("restaurant"),	
  3)	
  
parser.parse("hunt")	
  	
  	
  //	
  →	
  parser.WrongInput	
  
	
  
#2 メニューをパラメータとして渡す
Action型の内容は
Parserの処理理に依存しない
これも外に出したい
 
	
  
	
  
sealed	
  abstract	
  class	
  Action	
  
case	
  class	
  	
  GoTo(place:	
  String)	
  extends	
  Action	
  
case	
  object	
  Sleep	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  extends	
  Action	
  
	
  
class	
  Parser[A](menu:	
  Map[String,	
  A])	
  {	
  
	
  	
  sealed	
  abstract	
  class	
  State	
  
	
  	
  case	
  object	
  NoInput	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  extends	
  State	
  
	
  	
  case	
  class	
  Entering(action:	
  A,	
  count:	
  Int)	
  	
  	
  	
  extends	
  State	
  
	
  	
  case	
  class	
  Completed(action:	
  A)	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  extends	
  State	
  
	
  	
  case	
  object	
  WrongInput	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  extends	
  State	
  
	
  
	
  	
  def	
  parse(String	
  input):	
  State	
  =	
  ...	
  
	
  	
  def	
  maxMenuLength:	
  Int	
  =	
  ...	
  
}	
  
	
  
val	
  parser:	
  Parser[Action]	
  =	
  new	
  Parser(	
  
	
  	
  Map("hungry"	
  -­‐>	
  GoTo("restaurant"),	
  "tired"	
  -­‐>	
  Sleep,	
  ...))	
  
	
  
parser.parse("hun")	
  	
  	
  	
  //	
  →	
  parser.Entering(GoTo("restaurant"),	
  3)	
  
parser.parse("hunt")	
  	
  	
  //	
  →	
  parser.WrongInput	
  
#3 型も外から指定するように
 
	
  
	
  
sealed	
  abstract	
  class	
  Action	
  
case	
  class	
  	
  GoTo(place:	
  String)	
  extends	
  Action	
  
case	
  object	
  Sleep	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  extends	
  Action	
  
	
  
class	
  Parser[A](menu:	
  Map[String,	
  A])	
  {	
  
	
  	
  sealed	
  abstract	
  class	
  State	
  
	
  	
  case	
  object	
  NoInput	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  extends	
  State	
  
	
  	
  case	
  class	
  Entering(action:	
  A,	
  count:	
  Int)	
  	
  	
  	
  extends	
  State	
  
	
  	
  case	
  class	
  Completed(action:	
  A)	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  extends	
  State	
  
	
  	
  case	
  object	
  WrongInput	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  extends	
  State	
  
	
  
	
  	
  def	
  parse(String	
  input):	
  State	
  =	
  ...	
  
	
  	
  def	
  maxMenuLength:	
  Int	
  =	
  ...	
  
}	
  
	
  
val	
  parser:	
  Parser[Action]	
  =	
  new	
  Parser(	
  
	
  	
  Map("hungry"	
  -­‐>	
  GoTo("restaurant"),	
  "tired"	
  -­‐>	
  Sleep,	
  ...))	
  
	
  
parser.parse("hun")	
  	
  	
  	
  //	
  →	
  parser.Entering(GoTo("restaurant"),	
  3)	
  
parser.parse("hunt")	
  	
  	
  //	
  →	
  parser.WrongInput	
  
#3 型も外から指定するように
Parserモジュールは任意の型
で受け取れる
型パラメータがついた
abstract	
  class	
  Parser	
  {	
  
	
  	
  type	
  A	
  
	
  	
  def	
  menu:	
  Map[String,	
  A]	
  
	
  
	
  	
  sealed	
  abstract	
  class	
  State	
  
	
  	
  case	
  object	
  NoInput	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  extends	
  State	
  
	
  	
  case	
  class	
  Entering(action:	
  A,	
  count:	
  Int)	
  	
  	
  	
  extends	
  State	
  
	
  	
  case	
  class	
  Completed(action:	
  A)	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  extends	
  State	
  
	
  	
  case	
  object	
  WrongInput	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  extends	
  State	
  
	
  
	
  	
  def	
  parse(String	
  input):	
  State	
  =	
  ...	
  
	
  	
  def	
  maxMenuLength:	
  Int	
  =	
  ...	
  
}	
  
	
  
sealed	
  abstract	
  class	
  Action	
  
case	
  class	
  	
  GoTo(place:	
  String)	
  	
  	
  	
  	
  	
  	
  extends	
  Action	
  
case	
  object	
  Sleep	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  extends	
  Action	
  
	
  
val	
  parser:	
  Parser	
  =	
  new	
  Parser{	
  
	
  	
  type	
  A	
  =	
  Action	
  
	
  	
  val	
  menu	
  =	
  Map("hungry"	
  -­‐>	
  GoTo("restaurant"),	
  	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  "tired"	
  -­‐>	
  Sleep,	
  ...	
  )	
  
}	
  
	
  
parser.parse("hun")	
  	
  	
  	
  //	
  →	
  parser.Entering(GoTo(Restaurant),	
  3)	
  
parser.parse("hunt")	
  	
  	
  //	
  →	
  parser.WrongInput	
  
#4	
  型パラメータを抽象型で
	
  	
  	
  書き換えてみる
abstract	
  class	
  Parser	
  {	
  
	
  	
  type	
  A	
  
	
  	
  def	
  menu:	
  Map[String,	
  A]	
  
	
  
	
  	
  sealed	
  abstract	
  class	
  State	
  
	
  	
  case	
  object	
  NoInput	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  extends	
  State	
  
	
  	
  case	
  class	
  Entering(action:	
  A,	
  count:	
  Int)	
  	
  	
  	
  extends	
  State	
  
	
  	
  case	
  class	
  Completed(action:	
  A)	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  extends	
  State	
  
	
  	
  case	
  object	
  WrongInput	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  extends	
  State	
  
	
  
	
  	
  def	
  parse(String	
  input):	
  State	
  =	
  ...	
  
	
  	
  def	
  maxMenuLength:	
  Int	
  =	
  ...	
  
}	
  
	
  
sealed	
  abstract	
  class	
  Action	
  
case	
  class	
  	
  GoTo(place:	
  String)	
  	
  	
  	
  	
  	
  	
  extends	
  Action	
  
case	
  object	
  Sleep	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  extends	
  Action	
  
	
  
val	
  parser:	
  Parser	
  =	
  new	
  Parser{	
  
	
  	
  type	
  A	
  =	
  Action	
  
	
  	
  val	
  menu	
  =	
  Map("hungry"	
  -­‐>	
  GoTo("restaurant"),	
  	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  "tired"	
  -­‐>	
  Sleep,	
  ...	
  )	
  
}	
  
	
  
parser.parse("hun")	
  	
  	
  	
  //	
  →	
  parser.Entering(GoTo(Restaurant),	
  3)	
  
parser.parse("hunt")	
  	
  	
  //	
  →	
  parser.WrongInput	
  
ここで型を指定
これが抽象型
具体的な型は⼦子クラスで
#4	
  型パラメータを抽象型で
	
  	
  	
  書き換えてみる
abstract	
  class	
  Parser	
  {	
  
	
  	
  type	
  A	
  
	
  	
  def	
  menu:	
  Map[String,	
  A]	
  
	
  
	
  	
  sealed	
  abstract	
  class	
  State	
  
	
  	
  case	
  object	
  NoInput	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  extends	
  State	
  
	
  	
  case	
  class	
  Entering(action:	
  A,	
  count:	
  Int)	
  	
  	
  	
  extends	
  State	
  
	
  	
  case	
  class	
  Completed(action:	
  A)	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  extends	
  State	
  
	
  	
  case	
  object	
  WrongInput	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  extends	
  State	
  
	
  
	
  	
  def	
  parse(String	
  input):	
  State	
  =	
  ...	
  
	
  	
  def	
  maxMenuLength:	
  Int	
  =	
  ...	
  
}	
  
	
  
sealed	
  abstract	
  class	
  Action	
  
case	
  class	
  	
  GoTo(place:	
  String)	
  	
  	
  	
  	
  	
  	
  extends	
  Action	
  
case	
  object	
  Sleep	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  extends	
  Action	
  
	
  
val	
  parser:	
  Parser	
  =	
  new	
  Parser{	
  
	
  	
  type	
  A	
  =	
  Action	
  
	
  	
  val	
  menu	
  =	
  Map("hungry"	
  -­‐>	
  GoTo("restaurant"),	
  	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  "tired"	
  -­‐>	
  Sleep,	
  ...	
  )	
  
}	
  
	
  
parser.parse("hun")	
  	
  	
  	
  //	
  →	
  parser.Entering(GoTo(Restaurant),	
  3)	
  
parser.parse("hunt")	
  	
  	
  //	
  →	
  parser.WrongInput	
  
型パラメータが消えた
#4	
  型パラメータを抽象型で
	
  	
  	
  書き換えてみる
abstract	
  class	
  Parser	
  {	
  
	
  	
  type	
  Action	
  
	
  	
  def	
  menu:	
  Map[String,	
  Action]	
  
	
  
	
  	
  sealed	
  abstract	
  class	
  State	
  
	
  	
  case	
  object	
  NoInput	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  extends	
  State	
  
	
  	
  case	
  class	
  Entering(action:	
  Action,	
  count:	
  Int)	
  	
  extends	
  State	
  
	
  	
  case	
  class	
  Completed(action:	
  Action)	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  extends	
  State	
  
	
  	
  case	
  object	
  WrongInput	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  extends	
  State	
  
	
  
	
  	
  def	
  parse(String	
  input):	
  State	
  =	
  ...	
  
	
  	
  def	
  maxMenuLength:	
  Int	
  =	
  ...	
  
}	
  
	
  
	
  
val	
  parser:	
  Parser	
  =	
  new	
  Parser{	
  
	
  	
  sealed	
  abstract	
  class	
  Action	
  
	
  	
  case	
  class	
  	
  GoTo(place:	
  String)	
  	
  	
  	
  	
  	
  	
  extends	
  Action	
  
	
  	
  case	
  object	
  Sleep	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  extends	
  Action	
  
	
  
	
  	
  val	
  menu	
  =	
  Map("hungry"	
  -­‐>	
  GoTo("restaurant"),	
  	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  "tired"	
  -­‐>	
  Sleep,	
  ...	
  )	
  
}	
  
	
  
parser.parse("hun")	
  	
  	
  	
  //	
  →	
  parser.Entering(GoTo(Restaurant),	
  3)	
  
parser.parse("hunt")	
  	
  	
  //	
  →	
  parser.WrongInput	
  
#5	
  Action型の定義を
	
  	
  	
  ⼦子クラスに移す
abstract	
  class	
  Parser	
  {	
  
	
  	
  type	
  Action	
  
	
  	
  def	
  menu:	
  Map[String,	
  Action]	
  
	
  
	
  	
  sealed	
  abstract	
  class	
  State	
  
	
  	
  case	
  object	
  NoInput	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  extends	
  State	
  
	
  	
  case	
  class	
  Entering(action:	
  Action,	
  count:	
  Int)	
  	
  extends	
  State	
  
	
  	
  case	
  class	
  Completed(action:	
  Action)	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  extends	
  State	
  
	
  	
  case	
  object	
  WrongInput	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  extends	
  State	
  
	
  
	
  	
  def	
  parse(String	
  input):	
  State	
  =	
  ...	
  
	
  	
  def	
  maxMenuLength:	
  Int	
  =	
  ...	
  
}	
  
	
  
	
  
val	
  parser:	
  Parser	
  =	
  new	
  Parser{	
  
	
  	
  sealed	
  abstract	
  class	
  Action	
  
	
  	
  case	
  class	
  	
  GoTo(place:	
  String)	
  	
  	
  	
  	
  	
  	
  extends	
  Action	
  
	
  	
  case	
  object	
  Sleep	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  extends	
  Action	
  
	
  
	
  	
  val	
  menu	
  =	
  Map("hungry"	
  -­‐>	
  GoTo("restaurant"),	
  	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  "tired"	
  -­‐>	
  Sleep,	
  ...	
  )	
  
}	
  
	
  
parser.parse("hun")	
  	
  	
  	
  //	
  →	
  parser.Entering(GoTo(Restaurant),	
  3)	
  
parser.parse("hunt")	
  	
  	
  //	
  →	
  parser.WrongInput	
  
#5	
  Action型の定義を
	
  	
  	
  ⼦子クラスに移す
ここで抽象型の具体型を定義
abstract	
  class	
  Parser	
  {	
  
	
  	
  type	
  Action	
  
	
  	
  def	
  menu:	
  Map[String,	
  Action]	
  
	
  
	
  	
  sealed	
  abstract	
  class	
  State	
  
	
  	
  case	
  object	
  NoInput	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  extends	
  State	
  
	
  	
  case	
  class	
  Entering(action:	
  Action,	
  count:	
  Int)	
  	
  	
  	
  extends	
  State	
  
	
  	
  case	
  class	
  Completed(action:	
  Action)	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  extends	
  State	
  
	
  	
  case	
  object	
  WrongInput	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  extends	
  State	
  
	
  
	
  	
  def	
  parse(String	
  input):	
  State	
  =	
  ...	
  
	
  	
  def	
  maxMenuLength:	
  Int	
  =	
  ...	
  
}	
  
	
  
object	
  SomeParser	
  extends	
  Parser{	
  
	
  	
  sealed	
  abstract	
  class	
  Action	
  
	
  	
  case	
  class	
  	
  GoTo(place:	
  String)	
  	
  	
  	
  	
  	
  	
  extends	
  Action	
  
	
  	
  case	
  object	
  Sleep	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  extends	
  Action	
  
	
  
	
  	
  val	
  menu	
  =	
  Map("hungry"	
  -­‐>	
  GoTo("restaurant"),	
  "tired"	
  -­‐>	
  Sleep,	
  ...)	
  
}	
  
	
  
SomeParser.parse("hun")	
  //	
  →	
  SomeParser.Entering(GoTo("restaurant"),	
  3)	
  
SomeParser.parse("hunt")//	
  →	
  SomeParser.WrongInput	
  
#6 objectで定義する
パス依存型
•  別のモジュールに属する型は、別の型として扱われな
いと不不⾃自然
•  コンパイラは型が属するオブジェクトを辿って、型が
⼀一致するかを判断する。これをパス依存型という。
•  パス依存型により、モジュールとして素直に扱える。
(JavaのInner Classはパス依存型ではない)
val	
  someParser	
  =	
  new	
  Parser(...)	
  
val	
  antotherParser	
  =	
  new	
  Parser(...)	
  
	
  
someParser.parse(...)	
  	
  	
  	
  	
  //	
  →	
  someParser.During(...)	
  
anotherParser.parse(...)	
  	
  //	
  →	
  anotherParser.During(...)	
  
	
  
//	
  以下はコンパイルエラー	
  
val	
  state:	
  someParser.State	
  =	
  anotherParser.parse(...)	
  
Scalaのモジュールは簡単
(だったよね?)
•  オブジェクトをモジュールとして扱うのは、感覚的に
も素直に捉える事が出来る
•  モジュールを導⼊入する事に躊躇せず、気軽に使える
•  ScalaのクラスはMLではファンクタが対応するが...
※「プログラミング in OCaml 五⼗十嵐嵐淳著」より抜粋
難しい印
⾖豆知識識:全称型と存在型
•  Scala特有の⽤用語ではなく、⼀一般的な⽤用語として。
すべての型Aについて、モジュール内の関数に型がつく。
これは全称量量化(∀)に対応し全称型という。
ある型Aについて、モジュール内の関数に型がつく。
これは存在量量化 (∃)に対応し存在型という。
abstract	
  class	
  Klass{	
  
	
  	
  type	
  A	
  
	
  	
  def	
  show:	
  A	
  =>	
  String	
  
}	
  
	
  
abstract	
  class	
  Klass[A]{	
  
	
  	
  def	
  show:	
  A	
  =>	
  String	
  
}	
  
	
  
※ Scalaのキーワードとして存在型(forSome)があるが、上記のように抽象型
により存在型は実現できるため、forSomeはオワコン
クラスの機能を分解して考える
クラスと関数の類似性
•  クラスはパラメータが渡せるというけど...
•  パラメータを保持した関数が欲しいなら、
部分適⽤用した関数で実現できる
//	
  クラスの場合	
  
class	
  Parser[A](menu:	
  Map[String,	
  A]){	
  
	
  	
  def	
  parse(input:	
  String)	
  :	
  State[A]	
  =	
  ...	
  
}	
  
	
  
//	
  関数の場合	
  
def	
  parse[A](menu:	
  Map[String,	
  A])(input:	
  String):	
  State[A]	
  =	
  ...	
  
val	
  parser:	
  String	
  =>	
  State[Action]	
  =	
  parse(Map(...))	
  
	
  
⼀一つ⽬目の引数だけ渡す。
残りの⼆二つ⽬目の引数を渡した時に
関数が評価される
クラスとレコードの類似性
•  モジュールに2つ関数がある場合は
2つの名前付き関数の組を返す関数で実現できる
•  これはMLのレコードに対応する
//	
  クラスの場合	
  
class	
  Parser[A](menu:	
  Map[String,	
  A]){	
  
	
  	
  def	
  parse(input:	
  String)	
  :	
  State[A]	
  =	
  ...	
  
	
  	
  def	
  maxMenuLength:	
  Int	
  =	
  ...	
  
}	
  
	
  
//	
  関数の場合	
  
type	
  Parser[A]	
  =	
  {	
  
	
  	
  def	
  parse(input:	
  String)	
  :	
  State[A]	
  
	
  	
  def	
  maxMenuLength:	
  Int	
  
}	
  
def	
  createParser[A](menu:	
  Map[String,	
  A]):	
  Parser	
  =	
  ...	
  
	
  
オブジェクトへの機能の集約
•  MLでは値(関数)、モジュール、レコード、ヴァ
リアントはそれぞれが別々に分かれている
※ OCamlにはモジュールと値の相互変換をする機能があ
るが、明⽰示的に変換して⾏行行き来する
•  その観点で⾔言うと、
Scalaのオブジェクトやクラスはそれらが全部混
じってる
•  さらに、Java⽬目線で考えると、クラスメソッドや
パッケージもオブジェクトに集約されている
機能集約はよいのか?
•  オブジェクトが何でもできること⾃自体は⾃自然
•  実際の感覚として、なんでもオブジェクトなので、適当に
書いてから、徐々に書き換えやすいと感じてる
•  オブジェクトやクラスは簡単でお気軽で使いやすいと思う
•  客観的な⻑⾧長所はまとめれず...
(短所は、型推論論が弱いとか、代数データ型などのシンタッ
クスがごちゃごちゃしてるとかはっきりしてるけど)
私にとって、本当のオブジェクトのセマンティクスに関する素晴らしいことの
1つは、本当のオブジェクトが「端から端まで本当のコンピュータ
(RCATWD)」であることです。これによって、何でも表せる完全な能⼒力力をいつ
でも保持できます。    ー  アラン・ケイ
http://www.infoq.com/jp/news/2010/07/objects-smalltalk-erlang
trait
traitで分割
•  ひとつのモジュールが⼤大きくなってきたら、trait
で分断できる
object	
  Hoge	
  {	
  
	
  
	
  
	
  
	
  
	
  
	
  
	
  
}	
  
	
  
trait	
  SomePart{	
  
	
  
	
  
	
  
}	
  
	
  
trait	
  AnotherPart{	
  
	
  
	
  
	
  
}	
  
	
  
//	
  traitを合成(mix-­‐in)してモジュールを作る	
  
object	
  Hoge	
  extends	
  SomePart	
  	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  with	
  AnotherPart	
  
Some Functions
Another Functions
Some Functions
Another Functions
合成も簡単
•  インスタンス⽣生成時にもmix-inできる
//	
  objectでモジュールを作る	
  
object	
  Hoge	
  extends	
  SomePart	
  with	
  AnotherPart	
  
	
  
//	
  インスタンス⽣生成時にmix-­‐in	
  
val	
  hoge	
  =	
  new	
  SomePart	
  with	
  AnotherPart	
  
val	
  fuga	
  =	
  new	
  SomePart	
  with	
  YetAnotherPart	
  
	
  
//	
  条件によって、mix-­‐inされるものを切切り替える	
  
val	
  foo	
  =	
  if	
  (config.availableXXX)	
  new	
  SomePart	
  with	
  XXX	
  	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  else	
  new	
  SomePart	
  with	
  Default	
  
	
  
	
  
⾃自分型 (self type)
•  traitが他のtraitに依存することを⾃自分型により明
⽰示する。
object	
  Hoge	
  {	
  
	
  
	
  
	
  
	
  
	
  
	
  
	
  
}	
  
	
  
trait	
  SomePart{	
  
	
  
	
  
	
  
}	
  
	
  
trait	
  AnotherPart{	
  this	
  :	
  SomePart	
  =>	
  
	
  
	
  
	
  
}	
  
	
  
object	
  Hoge	
  extends	
  SomePart	
  	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  with	
  AnotherPart	
  
Some Functions
Another Functions
Some Functions
Another Functions
Call
⾃自分型
mix-in時に⾃自分型を満たさないと
コンパイルエラー
SomePart内の
関数が使える
traitによるシグネチャの記述
•  ⾃自分型として指定するtraitには具体的な実装は指
定しない⽅方がよい
–  宣⾔言時には型シグネチャだけが欲しくて
–  mix-inの時に実装が欲しい
trait	
  HogeSignature	
  {	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  //	
  シグネチャの宣⾔言	
  
	
  	
  def	
  func(arg:	
  Int):	
  String	
  
}	
  
	
  
trait	
  Fuga	
  {	
  this:	
  HogeSignature	
  =>	
  //	
  使う側はシグネチャのみ必要	
  
	
  	
  ...	
  
}	
  
	
  
trait	
  Hoge	
  extends	
  HogeSignature{	
  	
  	
  //	
  実装	
  
	
  	
  def	
  func(arg:	
  Int):	
  String	
  =	
  ...	
  
}	
  
	
  
object	
  SomeModule	
  extends	
  Fuga	
  with	
  Hoge	
  //	
  合成	
  
	
  
MLのsignatureとの対応
•  MLではモジュールの型が、そのモジュールの外部に対する
インターフェースを⽰示す。
–  モジュールの実装はstructure(struct)を、
–  その型の指定はsignature(sig)  を使う。
•  実装のないtraitはMLのsignatureに対応する
(*	
  OCamlのREPLで実⾏行行した場合	
  *)
# module Three = struct let x = 3 end;;	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  ← 実装
module Three : sig val x : int end 	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  ← 型
# module type X_int = sig val x : int end;;	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  ← 型
module type X_int = sig val x : int end	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  ← 型
# module Increment (M : X_int) = struct let x = M.x + 1 end;;	
  	
  	
  ← 実装
module Increment : functor (M : X_int) -> sig val x : int end	
  	
  	
  	
  	
  	
  	
  	
  ← 型
※「Real World Ocaml」Chapter 9 Functorより抜粋
その他
各種ライブラリでのtraitの⽤用例例
•  DSLの語彙を増やす
//	
  ScalaTestの例例	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  //	
  ShouldMatcherをmix-­‐inすると...	
  
class	
  HogeSpec	
  extends	
  Specification	
  with	
  ShouldMatcher	
  {	
  
	
  	
  //	
  中でshouldが使えるように	
  
	
  	
  "hoge"	
  in	
  {	
  
	
  	
  	
  	
  	
  hoge	
  should	
  equal	
  (3)	
  
	
  	
  }	
  
	
  
	
  
//	
  Akka(Actorなどの並列列分散ライブラリ)の例例	
  
	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  //	
  ActorLoggingをmix-­‐inすると...	
  
class	
  HogeActor	
  extends	
  Actor	
  with	
  ActorLogging	
  {	
  
	
  	
  	
  //	
  受け取ったメッセージがログに出⼒力力される	
  
	
  	
  	
  def	
  receive	
  =	
  {	
  ...	
  
	
  
•  機能を付与する
あってよかった
オブジェクト指向のあれ
あってよかった?
•  Scalaは基本的に関数型プログラミング
–  基本的に型と関数の定義
–  それらをまとめるモジュールにオブジェクトを使う
•  関数型プログラミングと相容れない
オブジェクト指向っぽい機能について、
使いどころを考える
あってよかった①
オブジェクトによる状態の管理理
•  例例えば、結果をキャッシュする場合
–  モジュールが状態を管理理する場合
–  pureに書くなら
状態を引き回すのが⾯面倒
→ Stateモナドで → 型が変わって⾯面倒
val	
  hoge	
  =	
  new	
  Hoge(bufferSize	
  =	
  100)	
  //	
  最新100件を記憶	
  
	
  
val	
  result1	
  =	
  hoge.heavyCalc(10)	
  
val	
  result2	
  =	
  hoge.heavyCalc(10)	
  
val	
  cache	
  =	
  Cache.empty(bufferSize	
  =	
  100)	
  
val	
  (result1,	
  cache1)	
  =	
  Hoge.heavyCalc(10,	
  cache)	
  
val	
  (result2,	
  cache2)	
  =	
  Hoge.heavyCalc(10,	
  cache1)	
  
あってよかった②
override
•  例例えば、テストごとでスタブを微妙に変えたい
•  他のoverrideの使い⽅方として、Stackable Traitという
テクニックもある
(詳細な説明)
http://www.artima.com/scalazine/articles/stackable_trait_pattern.html
"ほげのテスト"	
  in	
  {	
  
	
  	
  	
  val	
  stub	
  =	
  new	
  SomeStub{	
  override	
  def	
  hoge(...)	
  =	
  ...	
  }	
  
	
  	
  	
  ...	
  
}	
  
"ふがのテスト"	
  in	
  {	
  
	
  	
  	
  val	
  stub	
  =	
  new	
  SomeStub{	
  override	
  def	
  fuga(...)	
  =	
  ...	
  }	
  
	
  	
  	
  ...	
  
}	
  
trait	
  Hoge	
  with	
  Fuga{	
  
	
  	
  	
  	
  abstract	
  override	
  def	
  foo(x:	
  X)	
  =	
  super.foo(modify(x))	
  
	
  	
  	
  	
  ...	
  
あってよかった③
オブジェクト指向っぽい構造
•  例例えば、case objectを列列挙型として使う時に、
それぞれのパラメータをつけたいとき
•  ⼀一般的に
–  オブジェクト指向は対象を追加しやすい
–  関数型は操作を追加しやすい
sealed	
  abstract	
  class	
  ErrorReason(val	
  errorCode:	
  String)	
  
case	
  object	
  InvalidInput	
  	
  extends	
  ErrorReason("E001")	
  
case	
  object	
  NotAuthorized	
  extends	
  ErrorReason("E002")	
  
...	
  
結び
•  オブジェクト指向の定義はないし、⾔言語によって、
オブジェクトの⽴立立ち位置は異異なる
•  Scalaでは、オブジェクトはモジュールシステムの
ためにあり、関数プログラミングと融合している
•  関数型⾔言語的であるほど、優れた⾔言語であるわけ
でなく、オブジェクト指向にもメリットもある
•  Scalaならどちらのメリットも享受できる

Contenu connexe

Tendances

これから Haskell を書くにあたって
これから Haskell を書くにあたってこれから Haskell を書くにあたって
これから Haskell を書くにあたってTsuyoshi Matsudate
 
Feature Selection with R / in JP
Feature Selection with R / in JPFeature Selection with R / in JP
Feature Selection with R / in JPSercan Ahi
 
Rあんなときこんなとき(tokyo r#12)
Rあんなときこんなとき(tokyo r#12)Rあんなときこんなとき(tokyo r#12)
Rあんなときこんなとき(tokyo r#12)Shintaro Fukushima
 
関数プログラミング入門
関数プログラミング入門関数プログラミング入門
関数プログラミング入門Hideyuki Tanaka
 
Juliaによる予測モデル構築・評価
Juliaによる予測モデル構築・評価Juliaによる予測モデル構築・評価
Juliaによる予測モデル構築・評価Shintaro Fukushima
 
Pythonの処理系はどのように実装され,どのように動いているのか? 我々はその実態を調査すべくアマゾンへと飛んだ.
Pythonの処理系はどのように実装され,どのように動いているのか? 我々はその実態を調査すべくアマゾンへと飛んだ.Pythonの処理系はどのように実装され,どのように動いているのか? 我々はその実態を調査すべくアマゾンへと飛んだ.
Pythonの処理系はどのように実装され,どのように動いているのか? 我々はその実態を調査すべくアマゾンへと飛んだ.kiki utagawa
 
2013.07.15 はじパタlt scikit-learnで始める機械学習
2013.07.15 はじパタlt scikit-learnで始める機械学習2013.07.15 はじパタlt scikit-learnで始める機械学習
2013.07.15 はじパタlt scikit-learnで始める機械学習Motoya Wakiyama
 
constexpr idioms
constexpr idiomsconstexpr idioms
constexpr idiomsfimbul
 
Lisp Tutorial for Pythonista : Day 3
Lisp Tutorial for Pythonista : Day 3Lisp Tutorial for Pythonista : Day 3
Lisp Tutorial for Pythonista : Day 3Ransui Iso
 
boost::shared_ptr tutorial
boost::shared_ptr tutorialboost::shared_ptr tutorial
boost::shared_ptr tutorialNU_Pan
 
Frege, What a Non-strict Language
Frege, What a Non-strict LanguageFrege, What a Non-strict Language
Frege, What a Non-strict Languagey_taka_23
 
F#入門 ~関数プログラミングとは何か~
F#入門 ~関数プログラミングとは何か~F#入門 ~関数プログラミングとは何か~
F#入門 ~関数プログラミングとは何か~Nobuhisa Koizumi
 
Rで学ぶデータマイニングI 第8章〜第13章
Rで学ぶデータマイニングI 第8章〜第13章Rで学ぶデータマイニングI 第8章〜第13章
Rで学ぶデータマイニングI 第8章〜第13章Prunus 1350
 
不均衡データのクラス分類
不均衡データのクラス分類不均衡データのクラス分類
不均衡データのクラス分類Shintaro Fukushima
 
IdrisでWebアプリを書く
IdrisでWebアプリを書くIdrisでWebアプリを書く
IdrisでWebアプリを書くHideyuki Tanaka
 
BOF1-Scala02.pdf
BOF1-Scala02.pdfBOF1-Scala02.pdf
BOF1-Scala02.pdfHiroshi Ono
 
Pythonで始めるDropboxAPI
Pythonで始めるDropboxAPIPythonで始めるDropboxAPI
Pythonで始めるDropboxAPIDaisuke Igarashi
 

Tendances (20)

これから Haskell を書くにあたって
これから Haskell を書くにあたってこれから Haskell を書くにあたって
これから Haskell を書くにあたって
 
Feature Selection with R / in JP
Feature Selection with R / in JPFeature Selection with R / in JP
Feature Selection with R / in JP
 
たのしい関数型
たのしい関数型たのしい関数型
たのしい関数型
 
Rあんなときこんなとき(tokyo r#12)
Rあんなときこんなとき(tokyo r#12)Rあんなときこんなとき(tokyo r#12)
Rあんなときこんなとき(tokyo r#12)
 
関数プログラミング入門
関数プログラミング入門関数プログラミング入門
関数プログラミング入門
 
Juliaによる予測モデル構築・評価
Juliaによる予測モデル構築・評価Juliaによる予測モデル構築・評価
Juliaによる予測モデル構築・評価
 
Pythonの処理系はどのように実装され,どのように動いているのか? 我々はその実態を調査すべくアマゾンへと飛んだ.
Pythonの処理系はどのように実装され,どのように動いているのか? 我々はその実態を調査すべくアマゾンへと飛んだ.Pythonの処理系はどのように実装され,どのように動いているのか? 我々はその実態を調査すべくアマゾンへと飛んだ.
Pythonの処理系はどのように実装され,どのように動いているのか? 我々はその実態を調査すべくアマゾンへと飛んだ.
 
2013.07.15 はじパタlt scikit-learnで始める機械学習
2013.07.15 はじパタlt scikit-learnで始める機械学習2013.07.15 はじパタlt scikit-learnで始める機械学習
2013.07.15 はじパタlt scikit-learnで始める機械学習
 
constexpr idioms
constexpr idiomsconstexpr idioms
constexpr idioms
 
Lisp Tutorial for Pythonista : Day 3
Lisp Tutorial for Pythonista : Day 3Lisp Tutorial for Pythonista : Day 3
Lisp Tutorial for Pythonista : Day 3
 
boost::shared_ptr tutorial
boost::shared_ptr tutorialboost::shared_ptr tutorial
boost::shared_ptr tutorial
 
boost tour 1.48.0 all
boost tour 1.48.0 allboost tour 1.48.0 all
boost tour 1.48.0 all
 
Frege, What a Non-strict Language
Frege, What a Non-strict LanguageFrege, What a Non-strict Language
Frege, What a Non-strict Language
 
F#入門 ~関数プログラミングとは何か~
F#入門 ~関数プログラミングとは何か~F#入門 ~関数プログラミングとは何か~
F#入門 ~関数プログラミングとは何か~
 
Rで学ぶデータマイニングI 第8章〜第13章
Rで学ぶデータマイニングI 第8章〜第13章Rで学ぶデータマイニングI 第8章〜第13章
Rで学ぶデータマイニングI 第8章〜第13章
 
Python入門
Python入門Python入門
Python入門
 
不均衡データのクラス分類
不均衡データのクラス分類不均衡データのクラス分類
不均衡データのクラス分類
 
IdrisでWebアプリを書く
IdrisでWebアプリを書くIdrisでWebアプリを書く
IdrisでWebアプリを書く
 
BOF1-Scala02.pdf
BOF1-Scala02.pdfBOF1-Scala02.pdf
BOF1-Scala02.pdf
 
Pythonで始めるDropboxAPI
Pythonで始めるDropboxAPIPythonで始めるDropboxAPI
Pythonで始めるDropboxAPI
 

En vedette

Javaから始めるscalaっぽい書き方
Javaから始めるscalaっぽい書き方Javaから始めるscalaっぽい書き方
Javaから始めるscalaっぽい書き方Kenji Doi
 
Scalaで型クラス入門
Scalaで型クラス入門Scalaで型クラス入門
Scalaで型クラス入門Makoto Fukuhara
 
こわくない型クラス
こわくない型クラスこわくない型クラス
こわくない型クラスKota Mizushima
 
Elmで始めるFunctional Reactive Programming
Elmで始めるFunctional Reactive Programming Elmで始めるFunctional Reactive Programming
Elmで始めるFunctional Reactive Programming Yasuyuki Maeda
 
Preparing for distributed system failures using akka #ScalaMatsuri
Preparing for distributed system failures using akka #ScalaMatsuriPreparing for distributed system failures using akka #ScalaMatsuri
Preparing for distributed system failures using akka #ScalaMatsuriTIS Inc.
 
D言語をたまには真面目に紹介してみる
D言語をたまには真面目に紹介してみるD言語をたまには真面目に紹介してみる
D言語をたまには真面目に紹介してみるN Masahiro
 
AWS Lambda with Java/Scala #渋谷Java 第十二回
AWS Lambda with Java/Scala #渋谷Java 第十二回AWS Lambda with Java/Scala #渋谷Java 第十二回
AWS Lambda with Java/Scala #渋谷Java 第十二回hajime ni
 
第三回ありえる社内勉強会 「いわががのLombok」
第三回ありえる社内勉強会 「いわががのLombok」第三回ありえる社内勉強会 「いわががのLombok」
第三回ありえる社内勉強会 「いわががのLombok」yoshiaki iwanaga
 
Scalaで萌える関数型プログラミング[完全版]
Scalaで萌える関数型プログラミング[完全版]Scalaで萌える関数型プログラミング[完全版]
Scalaで萌える関数型プログラミング[完全版]Ra Zon
 
Skinny Meetup Tokyo 2 日本語スライド
Skinny Meetup Tokyo 2 日本語スライドSkinny Meetup Tokyo 2 日本語スライド
Skinny Meetup Tokyo 2 日本語スライドKazuhiro Sera
 
Introduction to Iteratees (Scala)
Introduction to Iteratees (Scala)Introduction to Iteratees (Scala)
Introduction to Iteratees (Scala)Alexander Lehmann
 
C++コミュニティーの中心でC++をDISる
C++コミュニティーの中心でC++をDISるC++コミュニティーの中心でC++をDISる
C++コミュニティーの中心でC++をDISるHideyuki Tanaka
 
Skinny Framework で始めた Scala
Skinny Framework で始めた ScalaSkinny Framework で始めた Scala
Skinny Framework で始めた ScalaRyuji Yamashita
 
あなたのScalaを爆速にする7つの方法(日本語版)
あなたのScalaを爆速にする7つの方法(日本語版)あなたのScalaを爆速にする7つの方法(日本語版)
あなたのScalaを爆速にする7つの方法(日本語版)x1 ichi
 

En vedette (20)

Javaから始めるscalaっぽい書き方
Javaから始めるscalaっぽい書き方Javaから始めるscalaっぽい書き方
Javaから始めるscalaっぽい書き方
 
Scalaで型クラス入門
Scalaで型クラス入門Scalaで型クラス入門
Scalaで型クラス入門
 
こわくない型クラス
こわくない型クラスこわくない型クラス
こわくない型クラス
 
Elmで始めるFunctional Reactive Programming
Elmで始めるFunctional Reactive Programming Elmで始めるFunctional Reactive Programming
Elmで始めるFunctional Reactive Programming
 
Purescript with Monad
Purescript with MonadPurescript with Monad
Purescript with Monad
 
Preparing for distributed system failures using akka #ScalaMatsuri
Preparing for distributed system failures using akka #ScalaMatsuriPreparing for distributed system failures using akka #ScalaMatsuri
Preparing for distributed system failures using akka #ScalaMatsuri
 
D言語をたまには真面目に紹介してみる
D言語をたまには真面目に紹介してみるD言語をたまには真面目に紹介してみる
D言語をたまには真面目に紹介してみる
 
AWS Lambda with Java/Scala #渋谷Java 第十二回
AWS Lambda with Java/Scala #渋谷Java 第十二回AWS Lambda with Java/Scala #渋谷Java 第十二回
AWS Lambda with Java/Scala #渋谷Java 第十二回
 
Elm overview
Elm overviewElm overview
Elm overview
 
第三回ありえる社内勉強会 「いわががのLombok」
第三回ありえる社内勉強会 「いわががのLombok」第三回ありえる社内勉強会 「いわががのLombok」
第三回ありえる社内勉強会 「いわががのLombok」
 
Scalaで萌える関数型プログラミング[完全版]
Scalaで萌える関数型プログラミング[完全版]Scalaで萌える関数型プログラミング[完全版]
Scalaで萌える関数型プログラミング[完全版]
 
Skinny Meetup Tokyo 2 日本語スライド
Skinny Meetup Tokyo 2 日本語スライドSkinny Meetup Tokyo 2 日本語スライド
Skinny Meetup Tokyo 2 日本語スライド
 
Introduction to Iteratees (Scala)
Introduction to Iteratees (Scala)Introduction to Iteratees (Scala)
Introduction to Iteratees (Scala)
 
Skinny 2 Update
Skinny 2 UpdateSkinny 2 Update
Skinny 2 Update
 
C++コミュニティーの中心でC++をDISる
C++コミュニティーの中心でC++をDISるC++コミュニティーの中心でC++をDISる
C++コミュニティーの中心でC++をDISる
 
ScalaMatsuri 2016
ScalaMatsuri 2016ScalaMatsuri 2016
ScalaMatsuri 2016
 
Skinny Framework で始めた Scala
Skinny Framework で始めた ScalaSkinny Framework で始めた Scala
Skinny Framework で始めた Scala
 
Xpath in-lens
Xpath in-lensXpath in-lens
Xpath in-lens
 
Scala with DDD
Scala with DDDScala with DDD
Scala with DDD
 
あなたのScalaを爆速にする7つの方法(日本語版)
あなたのScalaを爆速にする7つの方法(日本語版)あなたのScalaを爆速にする7つの方法(日本語版)
あなたのScalaを爆速にする7つの方法(日本語版)
 

Dernier

AWS の OpenShift サービス (ROSA) を使った OpenShift Virtualizationの始め方.pdf
AWS の OpenShift サービス (ROSA) を使った OpenShift Virtualizationの始め方.pdfAWS の OpenShift サービス (ROSA) を使った OpenShift Virtualizationの始め方.pdf
AWS の OpenShift サービス (ROSA) を使った OpenShift Virtualizationの始め方.pdfFumieNakayama
 
業務で生成AIを活用したい人のための生成AI入門講座(社外公開版:キンドリルジャパン社内勉強会:2024年4月発表)
業務で生成AIを活用したい人のための生成AI入門講座(社外公開版:キンドリルジャパン社内勉強会:2024年4月発表)業務で生成AIを活用したい人のための生成AI入門講座(社外公開版:キンドリルジャパン社内勉強会:2024年4月発表)
業務で生成AIを活用したい人のための生成AI入門講座(社外公開版:キンドリルジャパン社内勉強会:2024年4月発表)Hiroshi Tomioka
 
クラウドネイティブなサーバー仮想化基盤 - OpenShift Virtualization.pdf
クラウドネイティブなサーバー仮想化基盤 - OpenShift Virtualization.pdfクラウドネイティブなサーバー仮想化基盤 - OpenShift Virtualization.pdf
クラウドネイティブなサーバー仮想化基盤 - OpenShift Virtualization.pdfFumieNakayama
 
モーダル間の変換後の一致性とジャンル表を用いた解釈可能性の考察 ~Text-to-MusicとText-To-ImageかつImage-to-Music...
モーダル間の変換後の一致性とジャンル表を用いた解釈可能性の考察  ~Text-to-MusicとText-To-ImageかつImage-to-Music...モーダル間の変換後の一致性とジャンル表を用いた解釈可能性の考察  ~Text-to-MusicとText-To-ImageかつImage-to-Music...
モーダル間の変換後の一致性とジャンル表を用いた解釈可能性の考察 ~Text-to-MusicとText-To-ImageかつImage-to-Music...博三 太田
 
TataPixel: 畳の異方性を利用した切り替え可能なディスプレイの提案
TataPixel: 畳の異方性を利用した切り替え可能なディスプレイの提案TataPixel: 畳の異方性を利用した切り替え可能なディスプレイの提案
TataPixel: 畳の異方性を利用した切り替え可能なディスプレイの提案sugiuralab
 
デジタル・フォレンジックの最新動向(2024年4月27日情洛会総会特別講演スライド)
デジタル・フォレンジックの最新動向(2024年4月27日情洛会総会特別講演スライド)デジタル・フォレンジックの最新動向(2024年4月27日情洛会総会特別講演スライド)
デジタル・フォレンジックの最新動向(2024年4月27日情洛会総会特別講演スライド)UEHARA, Tetsutaro
 
CTO, VPoE, テックリードなどリーダーポジションに登用したくなるのはどんな人材か?
CTO, VPoE, テックリードなどリーダーポジションに登用したくなるのはどんな人材か?CTO, VPoE, テックリードなどリーダーポジションに登用したくなるのはどんな人材か?
CTO, VPoE, テックリードなどリーダーポジションに登用したくなるのはどんな人材か?akihisamiyanaga1
 
自分史上一番早い2024振り返り〜コロナ後、仕事は通常ペースに戻ったか〜 by IoT fullstack engineer
自分史上一番早い2024振り返り〜コロナ後、仕事は通常ペースに戻ったか〜 by IoT fullstack engineer自分史上一番早い2024振り返り〜コロナ後、仕事は通常ペースに戻ったか〜 by IoT fullstack engineer
自分史上一番早い2024振り返り〜コロナ後、仕事は通常ペースに戻ったか〜 by IoT fullstack engineerYuki Kikuchi
 

Dernier (8)

AWS の OpenShift サービス (ROSA) を使った OpenShift Virtualizationの始め方.pdf
AWS の OpenShift サービス (ROSA) を使った OpenShift Virtualizationの始め方.pdfAWS の OpenShift サービス (ROSA) を使った OpenShift Virtualizationの始め方.pdf
AWS の OpenShift サービス (ROSA) を使った OpenShift Virtualizationの始め方.pdf
 
業務で生成AIを活用したい人のための生成AI入門講座(社外公開版:キンドリルジャパン社内勉強会:2024年4月発表)
業務で生成AIを活用したい人のための生成AI入門講座(社外公開版:キンドリルジャパン社内勉強会:2024年4月発表)業務で生成AIを活用したい人のための生成AI入門講座(社外公開版:キンドリルジャパン社内勉強会:2024年4月発表)
業務で生成AIを活用したい人のための生成AI入門講座(社外公開版:キンドリルジャパン社内勉強会:2024年4月発表)
 
クラウドネイティブなサーバー仮想化基盤 - OpenShift Virtualization.pdf
クラウドネイティブなサーバー仮想化基盤 - OpenShift Virtualization.pdfクラウドネイティブなサーバー仮想化基盤 - OpenShift Virtualization.pdf
クラウドネイティブなサーバー仮想化基盤 - OpenShift Virtualization.pdf
 
モーダル間の変換後の一致性とジャンル表を用いた解釈可能性の考察 ~Text-to-MusicとText-To-ImageかつImage-to-Music...
モーダル間の変換後の一致性とジャンル表を用いた解釈可能性の考察  ~Text-to-MusicとText-To-ImageかつImage-to-Music...モーダル間の変換後の一致性とジャンル表を用いた解釈可能性の考察  ~Text-to-MusicとText-To-ImageかつImage-to-Music...
モーダル間の変換後の一致性とジャンル表を用いた解釈可能性の考察 ~Text-to-MusicとText-To-ImageかつImage-to-Music...
 
TataPixel: 畳の異方性を利用した切り替え可能なディスプレイの提案
TataPixel: 畳の異方性を利用した切り替え可能なディスプレイの提案TataPixel: 畳の異方性を利用した切り替え可能なディスプレイの提案
TataPixel: 畳の異方性を利用した切り替え可能なディスプレイの提案
 
デジタル・フォレンジックの最新動向(2024年4月27日情洛会総会特別講演スライド)
デジタル・フォレンジックの最新動向(2024年4月27日情洛会総会特別講演スライド)デジタル・フォレンジックの最新動向(2024年4月27日情洛会総会特別講演スライド)
デジタル・フォレンジックの最新動向(2024年4月27日情洛会総会特別講演スライド)
 
CTO, VPoE, テックリードなどリーダーポジションに登用したくなるのはどんな人材か?
CTO, VPoE, テックリードなどリーダーポジションに登用したくなるのはどんな人材か?CTO, VPoE, テックリードなどリーダーポジションに登用したくなるのはどんな人材か?
CTO, VPoE, テックリードなどリーダーポジションに登用したくなるのはどんな人材か?
 
自分史上一番早い2024振り返り〜コロナ後、仕事は通常ペースに戻ったか〜 by IoT fullstack engineer
自分史上一番早い2024振り返り〜コロナ後、仕事は通常ペースに戻ったか〜 by IoT fullstack engineer自分史上一番早い2024振り返り〜コロナ後、仕事は通常ペースに戻ったか〜 by IoT fullstack engineer
自分史上一番早い2024振り返り〜コロナ後、仕事は通常ペースに戻ったか〜 by IoT fullstack engineer
 

Scalaのオブジェクトの話

  • 1. 2014.6.25    第8回  Functional  忍者 ⼊入⼀一  前⽥田康⾏行行  (@maeda_̲) Scalaの オブジェクト の話
  • 2. ⾃自⼰己紹介 前⽥田康⾏行行  ( twitter : @maeda_ ) 名古屋在住  フリーランス 屋号:⼊入⼀一 ( http://www.illi-ichi.com )
  • 3. はじめに •  Scalaはオブジェクト指向⾔言語 –  既存資産を活かせるし、既存プログラマも分かりやすい –  強⼒力力なモジュールシステム 今回のテーマ Scalaの関数型プログラミングの中で オブジェクトをどのように使うのか?
  • 6. 関数型⾔言語との対応 Scala は 1. 関数型⾔言語のパーツをJavaのパーツにマッピングして 2. 使いやすいようにシンタックスなどを整えた⾔言語 パーツ ML Scala 関数 関数 メソッド 関数オブジェクト 代数データ型 ヴァリアント レコード case class case object モジュールシステム モジュール ファンクタ object class ※ Haskellは型クラスによりMLのモジュールシステムと同等の機能を実現可能 (参考)    ML Modules and Haskell Type Classes: A Constructive Comparison http://www.cse.unsw.edu.au/~chak/papers/modules-classes.pdf
  • 7. 関数型⾔言語との対応 Scala は 1. 関数型⾔言語のパーツをJavaのパーツにマッピングして 2. 使いやすいようにシンタックスなどを整えた⾔言語 パーツ ML Scala 関数 関数 メソッド 関数オブジェクト 代数データ型 ヴァリアント レコード case class case object モジュールシステム モジュール ファンクタ object class ※ Haskellは型クラスによりMLのモジュールシステムと同等の機能を実現可能 (参考)    ML Modules and Haskell Type Classes: A Constructive Comparison http://www.cse.unsw.edu.au/~chak/papers/modules-classes.pdf
  • 9. オブジェクトを作る •  objectキーワードにより シングルトンオブジェクト  (= モジュール) が作れる •  内部的には下記のようなイメージ object  Hoge  {      def  foo(...)  =  ...   }     Hoge.foo(...)              //  Hogeというモジュールのfooという関数を呼び出し   class  HogeClass(){      def  foo(...)  =  ...   }   val  Hoge  =  new  HogeClass()  
  • 10. クラスとは? •  パラメータ付きのモジュール •  パラメータを渡してインスタンス化 → モジュールができる class  Hoge(connectionString:  String){      def  foo(...)  =  ...   }     //  パラメータを渡して、モジュールの⽣生成   val  hoge  =  new  Hoge("jdbc:h2:mem:test")   hoge.foo(...)  
  • 11. オブジェクトがモジュールなので •  変数に代⼊入したり、関数に渡したり •  package名と同様にimportもできる class  Hoge(fuga:  Fuga){      import  fuga._    ...   }   Scalaのimportはどこでも書けるし、 スコープもある
  • 12. コンパニオンオブジェクト •  クラス名と同名のシングルトンオブジェクトは、 そのクラスのコンパニオンオブジェクトとなる。 •  コンパニオンオブジェクトにはそのクラスのヘルパー 関数を置く(Javaでいうstaticメソッド的なもの) •  コンストラクタにはクラス内で使うパラメータを渡す。 (下記のコード参照) //  privateをつけるとコンパニオンオブジェクトからしか⽣生成できない   class  Hoge  private  (...){  ...  }     object  Hoge  {      //  引数を加⼯工して、Hogeのインスタンスを⽣生成する関数      def  fromString(str:  String):  Hoge  =  new  Hoge(...)      def  fromFile(file:  File):  Hoge  =  new  Hoge(...)   }   ※ コンパニオンオブジェクトは対応するクラスと同じファイル内に記述すること ※ REPL上で試す場合は:pasteを使って⼊入⼒力力する
  • 14. お題 •  ⽂文字列列とそれに対応する動作を定義したマップが ある •  ⽂文字列列をパースして、マップのキーのうち、どれ をどこまで⼊入⼒力力したかを返す関数を作る val  menu:  Map[String,  Action]  =  Map(          "hungry"  -­‐>  GoTo("restaurant"),          "tired"  -­‐>  Sleep,          ...   )     Parser.parse("")              //  →  NoInput   Parser.parse("hun")        //  →  Entering(GoTo("restaurant"),  3)   Parser.parse("hunt")      //  →  WrongInput   Parser.parse("hungry")  //  →  Completed(GoTo("restaurant"))  
  • 15.     object  Parser  {      sealed  abstract  class  Action      case  class    GoTo(place:  String)  extends  Action      case  object  Sleep                              extends  Action        sealed  abstract  class  State      case  object  NoInput                                                                      extends  State      case  class  Entering(action:  Action,  count:  Int)              extends  State      case  class  Completed(action:  Action)                                    extends  State      case  object  WrongInput                                                                extends  State        val  menu:  Map[String,  Action]  =            Map("hungry"  -­‐>  GoTo("restaurant"),  "tired"  -­‐>  Sleep,  ...)        def  parse(String  input):  State  =  ...      def  maxMenuLength:  Int  =  ...   }     Parser.parse("hun")    //  →  Parser.Entering(Parser.GoTo("restaurant"),  3)   Parser.parse("hunt")  //  →  Parser.WrongInput   #1 objectでモジュールを作る
  • 16.     object  Parser  {      sealed  abstract  class  Action      case  class    GoTo(place:  String)  extends  Action      case  object  Sleep                              extends  Action        sealed  abstract  class  State      case  object  NoInput                                                                      extends  State      case  class  Entering(action:  Action,  count:  Int)              extends  State      case  class  Completed(action:  Action)                                    extends  State      case  object  WrongInput                                                                extends  State        val  menu:  Map[String,  Action]  =            Map("hungry"  -­‐>  GoTo("restaurant"),  "tired"  -­‐>  Sleep,  ...)        def  parse(String  input):  State  =  ...      def  maxMenuLength:  Int  =  ...   }     Parser.parse("hun")    //  →  Parser.Entering(Parser.GoTo("restaurant"),  3)   Parser.parse("hunt")  //  →  Parser.WrongInput   Parser モジュールの関数を呼び出す Parser モジュールを作って #1 objectでモジュールを作る
  • 17.     object  Parser  {      sealed  abstract  class  Action      case  class    GoTo(place:  String)  extends  Action      case  object  Sleep                              extends  Action        sealed  abstract  class  State      case  object  NoInput                                                                      extends  State      case  class  Entering(action:  Action,  count:  Int)              extends  State      case  class  Completed(action:  Action)                                    extends  State      case  object  WrongInput                                                                extends  State        val  menu:  Map[String,  Action]  =            Map("hungry"  -­‐>  GoTo("restaurant"),  "tired"  -­‐>  Sleep,  ...)        def  parse(String  input):  State  =  ...      def  maxMenuLength:  Int  =  ...   }     Parser.parse("hun")    //  →  Parser.Entering(Parser.GoTo("restaurant"),  3)   Parser.parse("hunt")  //  →  Parser.WrongInput   代数データ型の定義 #1 objectでモジュールを作る
  • 18.     object  Parser  {      sealed  abstract  class  Action      case  class    GoTo(place:  String)  extends  Action      case  object  Sleep                              extends  Action        sealed  abstract  class  State      case  object  NoInput                                                                      extends  State      case  class  Entering(action:  Action,  count:  Int)              extends  State      case  class  Completed(action:  Action)                                    extends  State      case  object  WrongInput                                                                extends  State        val  menu:  Map[String,  Action]  =            Map("hungry"  -­‐>  GoTo("restaurant"),  "tired"  -­‐>  Sleep,  ...)        def  parse(String  input):  State  =  ...      def  maxMenuLength:  Int  =  ...   }     Parser.parse("hun")    //  →  Parser.Entering(Parser.GoTo("restaurant"),  3)   Parser.parse("hunt")  //  →  Parser.WrongInput   ⽂文字列列と動作の対応を 記述するマップ #1 objectでモジュールを作る 関数の定義
  • 19.     object  Parser  {      sealed  abstract  class  Action      case  class    GoTo(place:  String)  extends  Action      case  object  Sleep                              extends  Action        sealed  abstract  class  State      case  object  NoInput                                                                      extends  State      case  class  Entering(action:  Action,  count:  Int)              extends  State      case  class  Completed(action:  Action)                                    extends  State      case  object  WrongInput                                                                extends  State        val  menu:  Map[String,  Action]  =            Map("hungry"  -­‐>  GoTo("restaurant"),  "tired"  -­‐>  Sleep,  ...)        def  parse(String  input):  State  =  ...      def  maxMenuLength:  Int  =  ...   }     Parser.parse("hun")    //  →  Parser.Entering(Parser.GoTo("restaurant"),  3)   Parser.parse("hunt")  //  →  Parser.WrongInput   #1 objectでモジュールを作る メニューを外部から 注⼊入したい
  • 20.       sealed  abstract  class  Action   case  class    GoTo(place:  String)  extends  Action   case  object  Sleep  extends  Action     class  Parser(menu:  Map[String,  Action])  {      sealed  abstract  class  State      case  object  NoInput                                                                      extends  State      case  class  Entering(action:  Action,  count:  Int)              extends  State      case  class  Completed(action:  Action)                                    extends  State      case  object  WrongInput                                                                extends  State        def  parse(String  input):  State  =  ...      def  maxMenuLength:  Int  =  ...   }     val  parser  =  new  Parser(      Map("hungry"  -­‐>  GoTo("restaurant"),  "tired"  -­‐>  Sleep,  ...))     parser.parse("hun")        //  →  parser.Entering(GoTo("restaurant"),  3)   parser.parse("hunt")      //  →  parser.WrongInput     #2 メニューをパラメータとして渡す
  • 21.       sealed  abstract  class  Action   case  class    GoTo(place:  String)  extends  Action   case  object  Sleep  extends  Action     class  Parser(menu:  Map[String,  Action])  {      sealed  abstract  class  State      case  object  NoInput                                                                      extends  State      case  class  Entering(action:  Action,  count:  Int)              extends  State      case  class  Completed(action:  Action)                                    extends  State      case  object  WrongInput                                                                extends  State        def  parse(String  input):  State  =  ...      def  maxMenuLength:  Int  =  ...   }     val  parser  =  new  Parser(      Map("hungry"  -­‐>  GoTo("restaurant"),  "tired"  -­‐>  Sleep,  ...))     parser.parse("hun")        //  →  parser.Entering(GoTo("restaurant"),  3)   parser.parse("hunt")      //  →  parser.WrongInput     #2 メニューをパラメータとして渡す classにして外からメニュー を渡せるように インスタンス化して モジュールを⽣生成
  • 22.       sealed  abstract  class  Action   case  class    GoTo(place:  String)  extends  Action   case  object  Sleep  extends  Action     class  Parser(menu:  Map[String,  Action])  {      sealed  abstract  class  State      case  object  NoInput                                                                      extends  State      case  class  Entering(action:  Action,  count:  Int)              extends  State      case  class  Completed(action:  Action)                                    extends  State      case  object  WrongInput                                                                extends  State        def  parse(String  input):  State  =  ...      def  maxMenuLength:  Int  =  ...   }     val  parser  =  new  Parser(      Map("hungry"  -­‐>  GoTo("restaurant"),  "tired"  -­‐>  Sleep,  ...))     parser.parse("hun")        //  →  parser.Entering(GoTo("restaurant"),  3)   parser.parse("hunt")      //  →  parser.WrongInput     #2 メニューをパラメータとして渡す Action型の内容は Parserの処理理に依存しない これも外に出したい
  • 23.       sealed  abstract  class  Action   case  class    GoTo(place:  String)  extends  Action   case  object  Sleep                              extends  Action     class  Parser[A](menu:  Map[String,  A])  {      sealed  abstract  class  State      case  object  NoInput                                                      extends  State      case  class  Entering(action:  A,  count:  Int)        extends  State      case  class  Completed(action:  A)                              extends  State      case  object  WrongInput                                                extends  State        def  parse(String  input):  State  =  ...      def  maxMenuLength:  Int  =  ...   }     val  parser:  Parser[Action]  =  new  Parser(      Map("hungry"  -­‐>  GoTo("restaurant"),  "tired"  -­‐>  Sleep,  ...))     parser.parse("hun")        //  →  parser.Entering(GoTo("restaurant"),  3)   parser.parse("hunt")      //  →  parser.WrongInput   #3 型も外から指定するように
  • 24.       sealed  abstract  class  Action   case  class    GoTo(place:  String)  extends  Action   case  object  Sleep                              extends  Action     class  Parser[A](menu:  Map[String,  A])  {      sealed  abstract  class  State      case  object  NoInput                                                      extends  State      case  class  Entering(action:  A,  count:  Int)        extends  State      case  class  Completed(action:  A)                              extends  State      case  object  WrongInput                                                extends  State        def  parse(String  input):  State  =  ...      def  maxMenuLength:  Int  =  ...   }     val  parser:  Parser[Action]  =  new  Parser(      Map("hungry"  -­‐>  GoTo("restaurant"),  "tired"  -­‐>  Sleep,  ...))     parser.parse("hun")        //  →  parser.Entering(GoTo("restaurant"),  3)   parser.parse("hunt")      //  →  parser.WrongInput   #3 型も外から指定するように Parserモジュールは任意の型 で受け取れる 型パラメータがついた
  • 25. abstract  class  Parser  {      type  A      def  menu:  Map[String,  A]        sealed  abstract  class  State      case  object  NoInput                                                      extends  State      case  class  Entering(action:  A,  count:  Int)        extends  State      case  class  Completed(action:  A)                              extends  State      case  object  WrongInput                                                extends  State        def  parse(String  input):  State  =  ...      def  maxMenuLength:  Int  =  ...   }     sealed  abstract  class  Action   case  class    GoTo(place:  String)              extends  Action   case  object  Sleep                                          extends  Action     val  parser:  Parser  =  new  Parser{      type  A  =  Action      val  menu  =  Map("hungry"  -­‐>  GoTo("restaurant"),                                      "tired"  -­‐>  Sleep,  ...  )   }     parser.parse("hun")        //  →  parser.Entering(GoTo(Restaurant),  3)   parser.parse("hunt")      //  →  parser.WrongInput   #4  型パラメータを抽象型で      書き換えてみる
  • 26. abstract  class  Parser  {      type  A      def  menu:  Map[String,  A]        sealed  abstract  class  State      case  object  NoInput                                                      extends  State      case  class  Entering(action:  A,  count:  Int)        extends  State      case  class  Completed(action:  A)                              extends  State      case  object  WrongInput                                                extends  State        def  parse(String  input):  State  =  ...      def  maxMenuLength:  Int  =  ...   }     sealed  abstract  class  Action   case  class    GoTo(place:  String)              extends  Action   case  object  Sleep                                          extends  Action     val  parser:  Parser  =  new  Parser{      type  A  =  Action      val  menu  =  Map("hungry"  -­‐>  GoTo("restaurant"),                                      "tired"  -­‐>  Sleep,  ...  )   }     parser.parse("hun")        //  →  parser.Entering(GoTo(Restaurant),  3)   parser.parse("hunt")      //  →  parser.WrongInput   ここで型を指定 これが抽象型 具体的な型は⼦子クラスで #4  型パラメータを抽象型で      書き換えてみる
  • 27. abstract  class  Parser  {      type  A      def  menu:  Map[String,  A]        sealed  abstract  class  State      case  object  NoInput                                                      extends  State      case  class  Entering(action:  A,  count:  Int)        extends  State      case  class  Completed(action:  A)                              extends  State      case  object  WrongInput                                                extends  State        def  parse(String  input):  State  =  ...      def  maxMenuLength:  Int  =  ...   }     sealed  abstract  class  Action   case  class    GoTo(place:  String)              extends  Action   case  object  Sleep                                          extends  Action     val  parser:  Parser  =  new  Parser{      type  A  =  Action      val  menu  =  Map("hungry"  -­‐>  GoTo("restaurant"),                                      "tired"  -­‐>  Sleep,  ...  )   }     parser.parse("hun")        //  →  parser.Entering(GoTo(Restaurant),  3)   parser.parse("hunt")      //  →  parser.WrongInput   型パラメータが消えた #4  型パラメータを抽象型で      書き換えてみる
  • 28. abstract  class  Parser  {      type  Action      def  menu:  Map[String,  Action]        sealed  abstract  class  State      case  object  NoInput                                                            extends  State      case  class  Entering(action:  Action,  count:  Int)    extends  State      case  class  Completed(action:  Action)                          extends  State      case  object  WrongInput                                                      extends  State        def  parse(String  input):  State  =  ...      def  maxMenuLength:  Int  =  ...   }       val  parser:  Parser  =  new  Parser{      sealed  abstract  class  Action      case  class    GoTo(place:  String)              extends  Action      case  object  Sleep                                          extends  Action        val  menu  =  Map("hungry"  -­‐>  GoTo("restaurant"),                                      "tired"  -­‐>  Sleep,  ...  )   }     parser.parse("hun")        //  →  parser.Entering(GoTo(Restaurant),  3)   parser.parse("hunt")      //  →  parser.WrongInput   #5  Action型の定義を      ⼦子クラスに移す
  • 29. abstract  class  Parser  {      type  Action      def  menu:  Map[String,  Action]        sealed  abstract  class  State      case  object  NoInput                                                            extends  State      case  class  Entering(action:  Action,  count:  Int)    extends  State      case  class  Completed(action:  Action)                          extends  State      case  object  WrongInput                                                      extends  State        def  parse(String  input):  State  =  ...      def  maxMenuLength:  Int  =  ...   }       val  parser:  Parser  =  new  Parser{      sealed  abstract  class  Action      case  class    GoTo(place:  String)              extends  Action      case  object  Sleep                                          extends  Action        val  menu  =  Map("hungry"  -­‐>  GoTo("restaurant"),                                      "tired"  -­‐>  Sleep,  ...  )   }     parser.parse("hun")        //  →  parser.Entering(GoTo(Restaurant),  3)   parser.parse("hunt")      //  →  parser.WrongInput   #5  Action型の定義を      ⼦子クラスに移す ここで抽象型の具体型を定義
  • 30. abstract  class  Parser  {      type  Action      def  menu:  Map[String,  Action]        sealed  abstract  class  State      case  object  NoInput                                                                extends  State      case  class  Entering(action:  Action,  count:  Int)        extends  State      case  class  Completed(action:  Action)                              extends  State      case  object  WrongInput                                                          extends  State        def  parse(String  input):  State  =  ...      def  maxMenuLength:  Int  =  ...   }     object  SomeParser  extends  Parser{      sealed  abstract  class  Action      case  class    GoTo(place:  String)              extends  Action      case  object  Sleep                                          extends  Action        val  menu  =  Map("hungry"  -­‐>  GoTo("restaurant"),  "tired"  -­‐>  Sleep,  ...)   }     SomeParser.parse("hun")  //  →  SomeParser.Entering(GoTo("restaurant"),  3)   SomeParser.parse("hunt")//  →  SomeParser.WrongInput   #6 objectで定義する
  • 31. パス依存型 •  別のモジュールに属する型は、別の型として扱われな いと不不⾃自然 •  コンパイラは型が属するオブジェクトを辿って、型が ⼀一致するかを判断する。これをパス依存型という。 •  パス依存型により、モジュールとして素直に扱える。 (JavaのInner Classはパス依存型ではない) val  someParser  =  new  Parser(...)   val  antotherParser  =  new  Parser(...)     someParser.parse(...)          //  →  someParser.During(...)   anotherParser.parse(...)    //  →  anotherParser.During(...)     //  以下はコンパイルエラー   val  state:  someParser.State  =  anotherParser.parse(...)  
  • 33. ⾖豆知識識:全称型と存在型 •  Scala特有の⽤用語ではなく、⼀一般的な⽤用語として。 すべての型Aについて、モジュール内の関数に型がつく。 これは全称量量化(∀)に対応し全称型という。 ある型Aについて、モジュール内の関数に型がつく。 これは存在量量化 (∃)に対応し存在型という。 abstract  class  Klass{      type  A      def  show:  A  =>  String   }     abstract  class  Klass[A]{      def  show:  A  =>  String   }     ※ Scalaのキーワードとして存在型(forSome)があるが、上記のように抽象型 により存在型は実現できるため、forSomeはオワコン
  • 35. クラスと関数の類似性 •  クラスはパラメータが渡せるというけど... •  パラメータを保持した関数が欲しいなら、 部分適⽤用した関数で実現できる //  クラスの場合   class  Parser[A](menu:  Map[String,  A]){      def  parse(input:  String)  :  State[A]  =  ...   }     //  関数の場合   def  parse[A](menu:  Map[String,  A])(input:  String):  State[A]  =  ...   val  parser:  String  =>  State[Action]  =  parse(Map(...))     ⼀一つ⽬目の引数だけ渡す。 残りの⼆二つ⽬目の引数を渡した時に 関数が評価される
  • 36. クラスとレコードの類似性 •  モジュールに2つ関数がある場合は 2つの名前付き関数の組を返す関数で実現できる •  これはMLのレコードに対応する //  クラスの場合   class  Parser[A](menu:  Map[String,  A]){      def  parse(input:  String)  :  State[A]  =  ...      def  maxMenuLength:  Int  =  ...   }     //  関数の場合   type  Parser[A]  =  {      def  parse(input:  String)  :  State[A]      def  maxMenuLength:  Int   }   def  createParser[A](menu:  Map[String,  A]):  Parser  =  ...    
  • 37. オブジェクトへの機能の集約 •  MLでは値(関数)、モジュール、レコード、ヴァ リアントはそれぞれが別々に分かれている ※ OCamlにはモジュールと値の相互変換をする機能があ るが、明⽰示的に変換して⾏行行き来する •  その観点で⾔言うと、 Scalaのオブジェクトやクラスはそれらが全部混 じってる •  さらに、Java⽬目線で考えると、クラスメソッドや パッケージもオブジェクトに集約されている
  • 38. 機能集約はよいのか? •  オブジェクトが何でもできること⾃自体は⾃自然 •  実際の感覚として、なんでもオブジェクトなので、適当に 書いてから、徐々に書き換えやすいと感じてる •  オブジェクトやクラスは簡単でお気軽で使いやすいと思う •  客観的な⻑⾧長所はまとめれず... (短所は、型推論論が弱いとか、代数データ型などのシンタッ クスがごちゃごちゃしてるとかはっきりしてるけど) 私にとって、本当のオブジェクトのセマンティクスに関する素晴らしいことの 1つは、本当のオブジェクトが「端から端まで本当のコンピュータ (RCATWD)」であることです。これによって、何でも表せる完全な能⼒力力をいつ でも保持できます。    ー  アラン・ケイ http://www.infoq.com/jp/news/2010/07/objects-smalltalk-erlang
  • 39. trait
  • 40. traitで分割 •  ひとつのモジュールが⼤大きくなってきたら、trait で分断できる object  Hoge  {                 }     trait  SomePart{         }     trait  AnotherPart{         }     //  traitを合成(mix-­‐in)してモジュールを作る   object  Hoge  extends  SomePart                            with  AnotherPart   Some Functions Another Functions Some Functions Another Functions
  • 41. 合成も簡単 •  インスタンス⽣生成時にもmix-inできる //  objectでモジュールを作る   object  Hoge  extends  SomePart  with  AnotherPart     //  インスタンス⽣生成時にmix-­‐in   val  hoge  =  new  SomePart  with  AnotherPart   val  fuga  =  new  SomePart  with  YetAnotherPart     //  条件によって、mix-­‐inされるものを切切り替える   val  foo  =  if  (config.availableXXX)  new  SomePart  with  XXX                        else  new  SomePart  with  Default      
  • 42. ⾃自分型 (self type) •  traitが他のtraitに依存することを⾃自分型により明 ⽰示する。 object  Hoge  {                 }     trait  SomePart{         }     trait  AnotherPart{  this  :  SomePart  =>         }     object  Hoge  extends  SomePart                            with  AnotherPart   Some Functions Another Functions Some Functions Another Functions Call ⾃自分型 mix-in時に⾃自分型を満たさないと コンパイルエラー SomePart内の 関数が使える
  • 43. traitによるシグネチャの記述 •  ⾃自分型として指定するtraitには具体的な実装は指 定しない⽅方がよい –  宣⾔言時には型シグネチャだけが欲しくて –  mix-inの時に実装が欲しい trait  HogeSignature  {                              //  シグネチャの宣⾔言      def  func(arg:  Int):  String   }     trait  Fuga  {  this:  HogeSignature  =>  //  使う側はシグネチャのみ必要      ...   }     trait  Hoge  extends  HogeSignature{      //  実装      def  func(arg:  Int):  String  =  ...   }     object  SomeModule  extends  Fuga  with  Hoge  //  合成    
  • 44. MLのsignatureとの対応 •  MLではモジュールの型が、そのモジュールの外部に対する インターフェースを⽰示す。 –  モジュールの実装はstructure(struct)を、 –  その型の指定はsignature(sig)  を使う。 •  実装のないtraitはMLのsignatureに対応する (*  OCamlのREPLで実⾏行行した場合  *) # module Three = struct let x = 3 end;;                                            ← 実装 module Three : sig val x : int end                                                          ← 型 # module type X_int = sig val x : int end;;                                        ← 型 module type X_int = sig val x : int end                                                  ← 型 # module Increment (M : X_int) = struct let x = M.x + 1 end;;      ← 実装 module Increment : functor (M : X_int) -> sig val x : int end                ← 型 ※「Real World Ocaml」Chapter 9 Functorより抜粋
  • 45. その他 各種ライブラリでのtraitの⽤用例例 •  DSLの語彙を増やす //  ScalaTestの例例                                                                        //  ShouldMatcherをmix-­‐inすると...   class  HogeSpec  extends  Specification  with  ShouldMatcher  {      //  中でshouldが使えるように      "hoge"  in  {            hoge  should  equal  (3)      }       //  Akka(Actorなどの並列列分散ライブラリ)の例例                                                                      //  ActorLoggingをmix-­‐inすると...   class  HogeActor  extends  Actor  with  ActorLogging  {        //  受け取ったメッセージがログに出⼒力力される        def  receive  =  {  ...     •  機能を付与する
  • 47. あってよかった? •  Scalaは基本的に関数型プログラミング –  基本的に型と関数の定義 –  それらをまとめるモジュールにオブジェクトを使う •  関数型プログラミングと相容れない オブジェクト指向っぽい機能について、 使いどころを考える
  • 48. あってよかった① オブジェクトによる状態の管理理 •  例例えば、結果をキャッシュする場合 –  モジュールが状態を管理理する場合 –  pureに書くなら 状態を引き回すのが⾯面倒 → Stateモナドで → 型が変わって⾯面倒 val  hoge  =  new  Hoge(bufferSize  =  100)  //  最新100件を記憶     val  result1  =  hoge.heavyCalc(10)   val  result2  =  hoge.heavyCalc(10)   val  cache  =  Cache.empty(bufferSize  =  100)   val  (result1,  cache1)  =  Hoge.heavyCalc(10,  cache)   val  (result2,  cache2)  =  Hoge.heavyCalc(10,  cache1)  
  • 49. あってよかった② override •  例例えば、テストごとでスタブを微妙に変えたい •  他のoverrideの使い⽅方として、Stackable Traitという テクニックもある (詳細な説明) http://www.artima.com/scalazine/articles/stackable_trait_pattern.html "ほげのテスト"  in  {        val  stub  =  new  SomeStub{  override  def  hoge(...)  =  ...  }        ...   }   "ふがのテスト"  in  {        val  stub  =  new  SomeStub{  override  def  fuga(...)  =  ...  }        ...   }   trait  Hoge  with  Fuga{          abstract  override  def  foo(x:  X)  =  super.foo(modify(x))          ...  
  • 50. あってよかった③ オブジェクト指向っぽい構造 •  例例えば、case objectを列列挙型として使う時に、 それぞれのパラメータをつけたいとき •  ⼀一般的に –  オブジェクト指向は対象を追加しやすい –  関数型は操作を追加しやすい sealed  abstract  class  ErrorReason(val  errorCode:  String)   case  object  InvalidInput    extends  ErrorReason("E001")   case  object  NotAuthorized  extends  ErrorReason("E002")   ...  
  • 51. 結び •  オブジェクト指向の定義はないし、⾔言語によって、 オブジェクトの⽴立立ち位置は異異なる •  Scalaでは、オブジェクトはモジュールシステムの ためにあり、関数プログラミングと融合している •  関数型⾔言語的であるほど、優れた⾔言語であるわけ でなく、オブジェクト指向にもメリットもある •  Scalaならどちらのメリットも享受できる