SlideShare a Scribd company logo
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ならどちらのメリットも享受できる

More Related Content

PDF
15分でざっくり分かるScala入門
PDF
Juliaで並列計算
PDF
Material
PDF
たのしい高階関数
PDF
Lisp tutorial for Pythonista : Day 2
PDF
これからの「言語」の話をしよう ―― 未来を生きるためのツール
PDF
Metaprogramming in JuliaLang
PDF
Python 機械学習プログラミング データ分析ライブラリー解説編
15分でざっくり分かるScala入門
Juliaで並列計算
Material
たのしい高階関数
Lisp tutorial for Pythonista : Day 2
これからの「言語」の話をしよう ―― 未来を生きるためのツール
Metaprogramming in JuliaLang
Python 機械学習プログラミング データ分析ライブラリー解説編

What's hot (20)

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

Viewers also liked (20)

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

Similar to Scalaのオブジェクトの話 (20)

PDF
BOF1-Scala02.pdf
PDF
BOF1-Scala02.pdf
PDF
Scalaプログラミング・マニアックス
PDF
モナドハンズオン前座
PDF
プログラミング言語Scala
PPTX
2018/2/20 Kotlin勉強会
PDF
Introduction to Scala Functional Programming
PDF
Monadicプログラミング マニアックス
PDF
(Ruby使いのための)Scalaで学ぶ関数型プログラミング
PDF
第2回関数型言語勉強会 大阪
PDF
関西Scala勉強会 パターンマッチング
PDF
MP in Scala
PDF
Refactoring point of Kotlin application
PDF
Monadic Programmingのススメ - Functional Reactive Programmingへのアプローチ
PDF
From Scala/Clojure to Kotlin
PDF
Scalaによる型安全なエラーハンドリング
PDF
実務者のためのかんたんScalaz
PDF
Introduction Xtend
PPTX
Xtend の紹介
PPTX
2013-12-08 西区プログラム勉強会
BOF1-Scala02.pdf
BOF1-Scala02.pdf
Scalaプログラミング・マニアックス
モナドハンズオン前座
プログラミング言語Scala
2018/2/20 Kotlin勉強会
Introduction to Scala Functional Programming
Monadicプログラミング マニアックス
(Ruby使いのための)Scalaで学ぶ関数型プログラミング
第2回関数型言語勉強会 大阪
関西Scala勉強会 パターンマッチング
MP in Scala
Refactoring point of Kotlin application
Monadic Programmingのススメ - Functional Reactive Programmingへのアプローチ
From Scala/Clojure to Kotlin
Scalaによる型安全なエラーハンドリング
実務者のためのかんたんScalaz
Introduction Xtend
Xtend の紹介
2013-12-08 西区プログラム勉強会

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ならどちらのメリットも享受できる