Friendly Functional Programming Wiem Zine Elabidine @WiemZin フレンドリーな関数型プログラミング
Scary Functional Programming Wiem Zine Elabidine @WiemZin Functor Monad 怖い関数型プログラミング
Friendly Functional Programming Wiem Zine Elabidine @WiemZin フレンドリーな関数型プログラミング
Plan Functional Programming Types and Functions Type classes 今日の予定、fp概要、型と関数 型クラスの流れで説明します
Paradigm Is a style and a way of writing your programs. Each programming language follow a programming style. パラダイムはプログラムを書く作法
Paradigm Is a style and a way of writing your programs. Each programming language follow a programming style. Scala combines object-oriented and functional programming. Scalaは、オブジェクト指向プログラミングと関数型プログラミングを組み合わせたものです。
Daniel Sophie
Daniel
Sophie
Declarative Imperative How I can do it? Declarative Mindset What I want to do? Imperative Mindset 宣言型の考え方と命令型の考え方
Functional programming A form of declarative programming 関数型プログラミングは宣言型プログラミングの1形態
immutability 03 Data & Functions Pure functions Composition 01 02 04 Functional programming 大まかに4つに分けて見ていきます
Pure functions Total Deterministic Free of side effects 純粋関数は決定的かつ副作用を持たない全域関数
Referential transparency When the function could be replaced by the result of its evaluation without affecting the meaning of the program. def sum(a: Int, b: Int): Int = a + b sum(2, 3) == 5 参照透過性は関数をその評価結果と置き換えても プログラムの振る舞いが変わらないこと
● Testability ● Refactoring ● Maintainability The benefits of FP FPの利点はテストのしやすさ メンテナビリティー
Types & Functions Abstraction 型と関数について
“A data types or a simple type is an attribute of data which tells the compiler or interpreter how the programmer intends to use the data.” -- Wikipedia Data Types データ型はデータ使用の意図を表す
“A data types or a simple type is an attribute of data which tells the compiler or interpreter how the programmer intends to use the data.” -- Wikipedia Data Types If it compiles, it works! コンパイルすれば動作します!
“Is a type formed by combining other types.” -- Wikipedia ADT (Algebraic Data Type) 代数的データ型は型の組み合わせ
Value types Int String Double Unit Boolean ... 値型
Product types Setting(true, true) Setting(false, true) Setting(false, true) Setting(false, false) case class Setting( audioEnabled: Boolean, videoEnabled: Boolean ) 直積型
Product types Setting(true, true) Setting(false, true) Setting(false, true) Setting(false, false) 2 x 2 = 4 4 possible values case class Setting( audioEnabled: Boolean, videoEnabled: Boolean ) 直積型
Sum types sealed trait Color case object Purple extends Color case object Red extends Color case object Yellow extends Color case object Green extends Color ? ? ? ? val color: Color = ??? 直和型
Sum types sealed trait Color case object Purple extends Color case object Red extends Color case object Yellow extends Color case object Green extends Color ? ? ? ? val color: Color = ??? 4 possible values 直和型
case class Form( topic: String, bgcolor: Color ) Geometry ADT ? ? ? ? val form: Form = Form(topic = ???, color = ???) ∞
sealed trait Topic case object Art extends Topic case object History extends Topic case object Philosophy extends Topic case object Geography extends Topic ADT
case class Form( topic: Topic, bgcolor: Color ) Geometry ADT ? ? ? ? val form: Form = Form(topic = ???, color = ???) ? ? ?
case class Form( topic: Topic, bgcolor: Color ) Geometry ADT ? ? ? ? val form: Form = Form(topic = ???, color = ???) ? ? ? 4 x 4 = 16 16 possible values
sealed trait Option[+A] case object None extends Option[Nothing] case class Some[A](a: A) extends Option[A] Parameterized ADT val choice: Option[Boolean] = ??? Some(true) Some(false) None パラメータ化された代数的データ型
sealed trait Option[+A] case object None extends Option[Nothing] case class Some[A](a: A) extends Option[A] Parameterized ADT val choice: Option[Int] = ??? Some(1) Some(157) None Some(2) Some(3) Some(4) Some(5) Some(6) Some(7) Some(8) Some(158) Some(159) Some(845) Some(880) Some(8810) Some(81945) Some(819447) Some(36841840) パラメータ化された代数的データ型
FP is the practice of composing programs using pure functions. Functions は純粋関数を用いてプログラムを書くための方法
A function takes data as an input and returns a data as an output Functions def isPositive(n: Int): Boolean = n > 0 関数はデータを受け取りデータを返す
A function could be defined: ● As a data type. First class functions type Predicate = Int => Boolean 関数そのものもデータ型
A function could be defined: ● As a data type. ● Using a literal syntax. First class functions (n: Int) => n > 0 関数リテラル構文を用いて定義できる
Higher order functions accept other functions as input and/or return functions as output. Higher-order functions 高階関数は別の関数を受け取るか 関数を戻り値として返す
Higher order functions accept other functions as input and/or return functions as output. Higher-order functions def checkOption(option: Option[Int], p: Int => Boolean): Boolean = option match { case Some(v) if p(v) => true case _ => false }
Higher order functions accept other functions as input and/or return functions as output. Higher-order functions def checkOption(option: Option[Int], p: Int => Boolean): Boolean = option match { case Some(v) if p(v) => true case _ => false } val isPositive: Int => Boolean = n => n > 0 checkOption(Some(14), isPositive)
Higher order functions accept other functions as input and/or return functions as output. Higher-order functions def checkOption(option: Option[Int], p: Int => Boolean): Boolean = option match { case Some(v) if p(v) => true case _ => false } val isPositive: Int => Boolean = _ > 0 checkOption(Some(14), isPositive)
Higher order functions accept other functions as input and/or return functions as output. Higher-order functions def checkOption(option: Option[Int], p: Int => Boolean): Boolean = option match { case Some(v) if p(v) => true case _ => false } checkOption(Some(14), n => n > 0)
Higher order functions accept other functions as input and/or return functions as output. Higher-order functions def checkOption(option: Option[Int], p: Int => Boolean): Boolean = option match { case Some(v) if p(v) => true case _ => false } checkOption(Some(14), _ > 0)
Type classes Add features to your types 型クラスは型に機能を与える
Type class Is a way to define certain operations for a given type.. A type class instance for a given type provides an implementation for these operations. 型に応じた演算を定義する方法 実装は特定の型クラスのインスタンスで定義される
Interface trait Translator { def translate( source: String, from: String, to: String): String } 翻訳インターフェイス
Interface trait Translator { def translate( source: String, from: String, to: String): String } Feature
Interface trait Translator { def translate( source: String, from: String, to: String): String } Language EN JA
Interface trait Translator { def translate( source: String, from: Language, to: Language): String } Audio String Document WebPage Discord ?
trait Translator[A] { def translate( source: A, from: Language, to: Language): A } パラメトリックなインターフェイス Parametric Interface
Use Discord auto-translation bot class DiscordTranslator extends Translator[DiscordMessage] { override def translate(text: DiscordMessage, from: Language, to: Language): DiscordMessage = ??? } def program(t: DiscordTranslator) = for { message <- consumeMessages (from, to) = detectLanguage(message) newMsg = t.translate(message,from,to) _ <- send(newMsg) } yield () Discord の自動翻訳ボットの例
Translate a simple text class StringTranslator extends Translator[String] { override def translate(text: String, from: Language, to: Language): String = ??? } def program(t: StringTranslator) = for { message <- consumeMessages (from, to) = detectLanguage(message) newMsg = t.translate(message,from,to) _ <- send(newMsg) } yield () 簡単なテキストの翻訳
What about Documents? class DocumentTranslator extends Translator[Document] { override def translate(text: Document, from: Language, to: Language): Document = ??? } def program(t: DocumentTranslator) = for { message <- consumeMessages (from, to) = detectLanguage(message) newMsg = t.translate(message,from,to) _ <- send(newMsg) } yield () Document ? 文書ファイルはどうしよう?
What about Audios? class AudioTranslator extends Translator[Audio] { override def translate(text: Audio, from: Language, to: Language): Audio = ??? } def program(t: AudioTranslator) = for { message <- consumeMessages (from, to) = detectLanguage(message) newMsg = t.translate(message,from,to) _ <- send(newMsg) } yield () Audio ? 音声はどうしよう?
Polymorphic program def program[A](t: Translator[A]) = for { message <- consumeMessages (from, to) = detectLanguage(message) newMsg = t.translate(message,from,to) _ <- send(newMsg) } yield () 多相的プログラム
Parametric Interface trait Translator[A] { def translate( text: A, from: Language, to: Language): A } パラメトリックなインターフェイス
Type class trait Translator[A] { def translate( text: A, from: Language, to: Language): A } object Translator { def apply[A](implicit t: Translator[A]): Translator[A] = t } 型クラス
Polymorphic program using context bounds def program[A: Translator] = for { message <- consumeMessages (from, to) = detectLanguage(message) newMsg = Translator[A].translate(message,from,to) _ <- send(newMsg) } yield () 型クラス
Polymorphic program using context bounds def program[A: Translator] = for { message <- consumeMessages (from, to) = detectLanguage(message) newMsg = Translator[A].translate(message,from,to) _ <- send(newMsg) } yield () def program[A](implicit t: Translator[A]) 構文を用いた多相プログラム
Type class instances implicit val discordTranslator = new Translator[DiscordMessage] { … } implicit val stringTranslator = new Translator[String] { … } implicit val documentTranslator = new Translator[Document] { … } implicit val audioTranslator = new Translator[Audio] { … } program[DiscordMessage] program[String] program[Document] program[Audio] 型クラスのインスタンス
Algebraic Data Structures empty combine Monoid combine Semigroup map flatMap Monad map Functor 代数的構造
Semigroup trait Semigroup[A] { def combine(a: A, b: A): A } object Semigroup { def apply[A](implicit s: Semigroup[A]): Semigroup[A] = s } Semigroup (半群)
Semigroup trait Semigroup[A] { def combine(a: A, b: A): A } object Semigroup { def apply[A](implicit s: Semigroup[A]): Semigroup[A] = s } Associativity combine(combine(a, b), c) == combine(a, combine(b, c)) Laws Semigroup則は結合律
Semigroup trait Semigroup[A] { def combine(a: A, b: A): A } object Semigroup { def apply[A](implicit s: Semigroup[A]): Semigroup[A] = s } Associativity (1 + 2) + 3 == 1 + (2 + 3) Int (+) Laws
Semigroup trait Semigroup[A] { def combine(a: A, b: A): A } object Semigroup { def apply[A](implicit s: Semigroup[A]): Semigroup[A] = s } Associativity (1 * 2) * 3 == 1 * (2 * 3) Int (*) Laws
Semigroup trait Semigroup[A] { def combine(a: A, b: A): A } object Semigroup { def apply[A](implicit s: Semigroup[A]): Semigroup[A] = s } Associativity Int (+, *) String (concat) Boolean(||, &&) Laws
Semigroup implicit val intSemigroup = new Semigroup[Int] { … } implicit val stringSemigroup = new Semigroup[String] { … } implicit val teamSemigroup = new Semigroup[Person] { … } ... Associativity Int (+, *) String (concat) Boolean(||, &&) Laws 🐣 🐣 🐼 🐻🧍 🧍♀ 🧍 🏻 ♀
Monoid trait Monoid[A] { def empty: A def combine(a: A, b: A): A } object Monoid { def apply[A](implicit m: Monoid[A]): Monoid[A] = m } モノイド
Monoid trait Monoid[A] { def empty: A def combine(a: A, b: A): A } object Monoid { def apply[A](implicit m: Monoid[A]): Monoid[A] = m } Identity combine(a, empty) == a combine(empty, a ) == a Associativity combine(combine(a, b), c) == combine(a, combine(b, c) Laws モノイド則は単位元と結合律
Monoid trait Monoid[A] { def empty: A def combine(a: A, b: A): A } object Monoid { def apply[A](implicit m: Monoid[A]): Monoid[A] = m } Eg. empty combinetype Int 1 * Int 0 + String “” concat Boolean true && Boolean false ||
Functor trait Functor[F[_]] { def map[A, B](f: A => B): F[A] => F[B] } object Functor { def apply[F[_]](implicit f : Functor[F]) : Functor[F] = f } Higher kinded type ファンクター
Functor trait Functor[F[_]] { def map[A, B](f: A => B): F[A] => F[B] } object Functor { def apply[F[_]](implicit f : Functor[F]) : Functor[F] = f } Identity ? composition ? Laws 単位元? 合成律?
The identity function def identity[A](a: A): A = a Identity composition ? Laws 恒等関数
The identity law def identity[A](a: A): A = a //REMINDER: def map[A, B](f: A => B): F[A] => F[B] map(identity) == identity Identity composition ? Laws 単位元
trait Function1[-B, +C] { def apply(b: B): C def compose[A](g: A => B): A => C = a => apply(g(a)) } Identity composition Laws The compose function 合成関数
trait Function1[-B, +C] { def apply(b: B): C def compose[A](g: A => B): A => C = a => apply(g(a)) } f: A => B g: B => C h: A => C h = a => g(f(a)) === g compose f f ° g The compose function
trait Function1[-B, +C] { def apply(b: B): C def compose[A](g: A => B): A => C = a => apply(g(a)) } //REMINDER: def map[A, B](f: A => B): F[A] => F[B] map(g compose f) == map(g) compose map(f) Laws The composition law Identity composition
implicit val optionFunctor: Functor[Option] = new Functor[Option] { override def map[A, B](f: A => B): Option[A] => Option[B] = { case None => None case Some(a) => Some(f(a)) } } Example for a Functor instance Functor[Option] ファンクター・インスタンスの例
implicit val optionFunctor: Functor[Option] = new Functor[Option] { override def map[A, B](f: A => B): Option[A] => Option[B] = { case None => None case Some(a) => Some(f(a)) } } Identity law for: Functor[Option] f: identity f: A => A None => None Some(a) => Some(a) identity Functor[Option] の単位元
implicit val optionFunctor: Functor[Option] = new Functor[Option] { override def map[A, B](f: A => B): Option[A] => Option[B] = { case None => None case Some(a) => Some(f(a)) } } Composition law for: Functor[Option] Identity Law map(identity)(Some(1)) == Some(1) map(identity)(None) == None def increment(i: Int): Int def toString(i: Int): String map(toString compose increment) == map(toString) compose map(increment) Some(41) Functor[Option] の合成律
implicit val optionFunctor: Functor[Option] = new Functor[Option] { override def map[A, B](f: A => B): Option[A] => Option[B] = { case None => None case Some(a) => Some(f(a)) } } Composition law for: Functor[Option] Identity Law map(identity)(Some(1)) == Some(1) map(identity)(None) == None def increment(i: Int): Int def toString(i: Int): String map(toString compose increment) == map(toString) compose map(increment) Some(41) Some(“42”)
implicit val optionFunctor: Functor[Option] = new Functor[Option] { override def map[A, B](f: A => B): Option[A] => Option[B] = { case None => None case Some(a) => Some(f(a)) } } Composition law for: Functor[Option] Identity Law map(identity)(Some(1)) == Some(1) map(identity)(None) == None def increment(i: Int): Int def toString(i: Int): String map(toString compose increment) == map(toString) compose map(increment) Some(41) Some(“42”) Some(“42”)
Monad trait Monad[F[_]] { def map[A, B](f: A => B): F[A] => F[B] def flatMap[A, B](f: A => F[B]): F[A] => F[B] } object Monad { def apply[F[_]](implicit m: Monad[F]) : Monad[F] = m } Higher kinded type モナド
Monad trait Monad[F[_]] { def point[A](a: A): F[A] def map[A, B](f: A => B): F[A] => F[B] def flatMap[A, B](f: A => F[B]): F[A] => F[B] } object Monad { def apply[F[_]](implicit m: Monad[F]) : Monad[F] = m } モナド
Monad trait Monad[F[_]] { def point[A](a: A): F[A] def map[A, B](f: A => B): F[A] => F[B] def flatMap[A, B](f: A => F[B]): F[A] => F[B] } object Monad { def apply[F[_]](implicit m: Monad[F]) : Monad[F] = m } Left identity ? Right identity Associativity ? Laws 左単位元 、右単位元 、結合律
Left identity def increment(a: Int): Option[Int] = Some(a + 1) Some(42).flatMap(a => increment(2)) == increment(2) Left identity Right identity Associativity ? Laws 左単位元
Right identity Some(42).flatMap(Some(_)) == Some(42) Left identity Right identity Associativity ? Laws 右単位元
Associativity def increment(i: Int): Option[Int] = Some(i + 1) def decrement(i: Int): Option[Int] = Some(i - 1) Some(42).flatMap(increment).flatMap(decrement) == Some(42).flatMap(v => increment(v).flatMap(decrement)) Left identity Right identity Associativity Laws 結合律
Monads in real life IOモナドのコンテキストで演算する Haskeller
You can checkout the Scala functional programming libraries: ● Cats Github: https://github.com/typelevel/cats doc: https://typelevel.org/cats ● Scalaz: https://github.com/scalaz/scalaz ● Zio Prelude: https://github.com/zio/zio-prelude Talks by: ● John De Goes and Adam Fraser: “Reimagining Functional Type Classes” ● Jakub Kozlowski: “Fantastic Monads and where to find them” Resources 次へのリソース
FP is AWESOME FP って最高
CREDITS: This presentation template was created by Slidesgo, including icons by Flaticon, and infographics & images by Freepik THANKS! Please keep this slide for attribution @WiemZin ご清聴ありがとうございました

Friendly Functional Programming

  • 1.
    Friendly Functional Programming Wiem ZineElabidine @WiemZin フレンドリーな関数型プログラミング
  • 2.
    Scary Functional Programming Wiem ZineElabidine @WiemZin Functor Monad 怖い関数型プログラミング
  • 3.
    Friendly Functional Programming Wiem ZineElabidine @WiemZin フレンドリーな関数型プログラミング
  • 4.
    Plan Functional Programming Types and FunctionsType classes 今日の予定、fp概要、型と関数 型クラスの流れで説明します
  • 5.
    Paradigm Is a styleand a way of writing your programs. Each programming language follow a programming style. パラダイムはプログラムを書く作法
  • 6.
    Paradigm Is a styleand a way of writing your programs. Each programming language follow a programming style. Scala combines object-oriented and functional programming. Scalaは、オブジェクト指向プログラミングと関数型プログラミングを組み合わせたものです。
  • 7.
  • 8.
  • 12.
  • 15.
    Declarative Imperative How I cando it? Declarative Mindset What I want to do? Imperative Mindset 宣言型の考え方と命令型の考え方
  • 16.
    Functional programming A formof declarative programming 関数型プログラミングは宣言型プログラミングの1形態
  • 17.
    immutability 03 Data & FunctionsPure functions Composition 01 02 04 Functional programming 大まかに4つに分けて見ていきます
  • 18.
    Pure functions Total DeterministicFree of side effects 純粋関数は決定的かつ副作用を持たない全域関数
  • 19.
    Referential transparency When thefunction could be replaced by the result of its evaluation without affecting the meaning of the program. def sum(a: Int, b: Int): Int = a + b sum(2, 3) == 5 参照透過性は関数をその評価結果と置き換えても プログラムの振る舞いが変わらないこと
  • 20.
    ● Testability ● Refactoring ●Maintainability The benefits of FP FPの利点はテストのしやすさ メンテナビリティー
  • 21.
  • 22.
    “A data typesor a simple type is an attribute of data which tells the compiler or interpreter how the programmer intends to use the data.” -- Wikipedia Data Types データ型はデータ使用の意図を表す
  • 23.
    “A data typesor a simple type is an attribute of data which tells the compiler or interpreter how the programmer intends to use the data.” -- Wikipedia Data Types If it compiles, it works! コンパイルすれば動作します!
  • 24.
    “Is a typeformed by combining other types.” -- Wikipedia ADT (Algebraic Data Type) 代数的データ型は型の組み合わせ
  • 25.
  • 26.
    Product types Setting(true, true) Setting(false,true) Setting(false, true) Setting(false, false) case class Setting( audioEnabled: Boolean, videoEnabled: Boolean ) 直積型
  • 27.
    Product types Setting(true, true) Setting(false,true) Setting(false, true) Setting(false, false) 2 x 2 = 4 4 possible values case class Setting( audioEnabled: Boolean, videoEnabled: Boolean ) 直積型
  • 28.
    Sum types sealed traitColor case object Purple extends Color case object Red extends Color case object Yellow extends Color case object Green extends Color ? ? ? ? val color: Color = ??? 直和型
  • 29.
    Sum types sealed traitColor case object Purple extends Color case object Red extends Color case object Yellow extends Color case object Green extends Color ? ? ? ? val color: Color = ??? 4 possible values 直和型
  • 30.
    case class Form( topic:String, bgcolor: Color ) Geometry ADT ? ? ? ? val form: Form = Form(topic = ???, color = ???) ∞
  • 31.
    sealed trait Topic caseobject Art extends Topic case object History extends Topic case object Philosophy extends Topic case object Geography extends Topic ADT
  • 32.
    case class Form( topic:Topic, bgcolor: Color ) Geometry ADT ? ? ? ? val form: Form = Form(topic = ???, color = ???) ? ? ?
  • 33.
    case class Form( topic:Topic, bgcolor: Color ) Geometry ADT ? ? ? ? val form: Form = Form(topic = ???, color = ???) ? ? ? 4 x 4 = 16 16 possible values
  • 34.
    sealed trait Option[+A] caseobject None extends Option[Nothing] case class Some[A](a: A) extends Option[A] Parameterized ADT val choice: Option[Boolean] = ??? Some(true) Some(false) None パラメータ化された代数的データ型
  • 35.
    sealed trait Option[+A] caseobject None extends Option[Nothing] case class Some[A](a: A) extends Option[A] Parameterized ADT val choice: Option[Int] = ??? Some(1) Some(157) None Some(2) Some(3) Some(4) Some(5) Some(6) Some(7) Some(8) Some(158) Some(159) Some(845) Some(880) Some(8810) Some(81945) Some(819447) Some(36841840) パラメータ化された代数的データ型
  • 36.
    FP is thepractice of composing programs using pure functions. Functions は純粋関数を用いてプログラムを書くための方法
  • 37.
    A function takesdata as an input and returns a data as an output Functions def isPositive(n: Int): Boolean = n > 0 関数はデータを受け取りデータを返す
  • 38.
    A function couldbe defined: ● As a data type. First class functions type Predicate = Int => Boolean 関数そのものもデータ型
  • 39.
    A function couldbe defined: ● As a data type. ● Using a literal syntax. First class functions (n: Int) => n > 0 関数リテラル構文を用いて定義できる
  • 40.
    Higher order functionsaccept other functions as input and/or return functions as output. Higher-order functions 高階関数は別の関数を受け取るか 関数を戻り値として返す
  • 41.
    Higher order functionsaccept other functions as input and/or return functions as output. Higher-order functions def checkOption(option: Option[Int], p: Int => Boolean): Boolean = option match { case Some(v) if p(v) => true case _ => false }
  • 42.
    Higher order functionsaccept other functions as input and/or return functions as output. Higher-order functions def checkOption(option: Option[Int], p: Int => Boolean): Boolean = option match { case Some(v) if p(v) => true case _ => false } val isPositive: Int => Boolean = n => n > 0 checkOption(Some(14), isPositive)
  • 43.
    Higher order functionsaccept other functions as input and/or return functions as output. Higher-order functions def checkOption(option: Option[Int], p: Int => Boolean): Boolean = option match { case Some(v) if p(v) => true case _ => false } val isPositive: Int => Boolean = _ > 0 checkOption(Some(14), isPositive)
  • 44.
    Higher order functionsaccept other functions as input and/or return functions as output. Higher-order functions def checkOption(option: Option[Int], p: Int => Boolean): Boolean = option match { case Some(v) if p(v) => true case _ => false } checkOption(Some(14), n => n > 0)
  • 45.
    Higher order functionsaccept other functions as input and/or return functions as output. Higher-order functions def checkOption(option: Option[Int], p: Int => Boolean): Boolean = option match { case Some(v) if p(v) => true case _ => false } checkOption(Some(14), _ > 0)
  • 46.
    Type classes Add featuresto your types 型クラスは型に機能を与える
  • 47.
    Type class Is away to define certain operations for a given type.. A type class instance for a given type provides an implementation for these operations. 型に応じた演算を定義する方法 実装は特定の型クラスのインスタンスで定義される
  • 48.
    Interface trait Translator { deftranslate( source: String, from: String, to: String): String } 翻訳インターフェイス
  • 49.
    Interface trait Translator { deftranslate( source: String, from: String, to: String): String } Feature
  • 50.
    Interface trait Translator { deftranslate( source: String, from: String, to: String): String } Language EN JA
  • 51.
    Interface trait Translator { deftranslate( source: String, from: Language, to: Language): String } Audio String Document WebPage Discord ?
  • 52.
    trait Translator[A] { deftranslate( source: A, from: Language, to: Language): A } パラメトリックなインターフェイス Parametric Interface
  • 53.
    Use Discord auto-translationbot class DiscordTranslator extends Translator[DiscordMessage] { override def translate(text: DiscordMessage, from: Language, to: Language): DiscordMessage = ??? } def program(t: DiscordTranslator) = for { message <- consumeMessages (from, to) = detectLanguage(message) newMsg = t.translate(message,from,to) _ <- send(newMsg) } yield () Discord の自動翻訳ボットの例
  • 54.
    Translate a simpletext class StringTranslator extends Translator[String] { override def translate(text: String, from: Language, to: Language): String = ??? } def program(t: StringTranslator) = for { message <- consumeMessages (from, to) = detectLanguage(message) newMsg = t.translate(message,from,to) _ <- send(newMsg) } yield () 簡単なテキストの翻訳
  • 55.
    What about Documents? classDocumentTranslator extends Translator[Document] { override def translate(text: Document, from: Language, to: Language): Document = ??? } def program(t: DocumentTranslator) = for { message <- consumeMessages (from, to) = detectLanguage(message) newMsg = t.translate(message,from,to) _ <- send(newMsg) } yield () Document ? 文書ファイルはどうしよう?
  • 56.
    What about Audios? classAudioTranslator extends Translator[Audio] { override def translate(text: Audio, from: Language, to: Language): Audio = ??? } def program(t: AudioTranslator) = for { message <- consumeMessages (from, to) = detectLanguage(message) newMsg = t.translate(message,from,to) _ <- send(newMsg) } yield () Audio ? 音声はどうしよう?
  • 57.
    Polymorphic program def program[A](t:Translator[A]) = for { message <- consumeMessages (from, to) = detectLanguage(message) newMsg = t.translate(message,from,to) _ <- send(newMsg) } yield () 多相的プログラム
  • 58.
    Parametric Interface trait Translator[A]{ def translate( text: A, from: Language, to: Language): A } パラメトリックなインターフェイス
  • 59.
    Type class trait Translator[A]{ def translate( text: A, from: Language, to: Language): A } object Translator { def apply[A](implicit t: Translator[A]): Translator[A] = t } 型クラス
  • 60.
    Polymorphic program usingcontext bounds def program[A: Translator] = for { message <- consumeMessages (from, to) = detectLanguage(message) newMsg = Translator[A].translate(message,from,to) _ <- send(newMsg) } yield () 型クラス
  • 61.
    Polymorphic program usingcontext bounds def program[A: Translator] = for { message <- consumeMessages (from, to) = detectLanguage(message) newMsg = Translator[A].translate(message,from,to) _ <- send(newMsg) } yield () def program[A](implicit t: Translator[A]) 構文を用いた多相プログラム
  • 62.
    Type class instances implicitval discordTranslator = new Translator[DiscordMessage] { … } implicit val stringTranslator = new Translator[String] { … } implicit val documentTranslator = new Translator[Document] { … } implicit val audioTranslator = new Translator[Audio] { … } program[DiscordMessage] program[String] program[Document] program[Audio] 型クラスのインスタンス
  • 63.
  • 64.
    Semigroup trait Semigroup[A] { defcombine(a: A, b: A): A } object Semigroup { def apply[A](implicit s: Semigroup[A]): Semigroup[A] = s } Semigroup (半群)
  • 65.
    Semigroup trait Semigroup[A] { defcombine(a: A, b: A): A } object Semigroup { def apply[A](implicit s: Semigroup[A]): Semigroup[A] = s } Associativity combine(combine(a, b), c) == combine(a, combine(b, c)) Laws Semigroup則は結合律
  • 66.
    Semigroup trait Semigroup[A] { defcombine(a: A, b: A): A } object Semigroup { def apply[A](implicit s: Semigroup[A]): Semigroup[A] = s } Associativity (1 + 2) + 3 == 1 + (2 + 3) Int (+) Laws
  • 67.
    Semigroup trait Semigroup[A] { defcombine(a: A, b: A): A } object Semigroup { def apply[A](implicit s: Semigroup[A]): Semigroup[A] = s } Associativity (1 * 2) * 3 == 1 * (2 * 3) Int (*) Laws
  • 68.
    Semigroup trait Semigroup[A] { defcombine(a: A, b: A): A } object Semigroup { def apply[A](implicit s: Semigroup[A]): Semigroup[A] = s } Associativity Int (+, *) String (concat) Boolean(||, &&) Laws
  • 69.
    Semigroup implicit val intSemigroup= new Semigroup[Int] { … } implicit val stringSemigroup = new Semigroup[String] { … } implicit val teamSemigroup = new Semigroup[Person] { … } ... Associativity Int (+, *) String (concat) Boolean(||, &&) Laws 🐣 🐣 🐼 🐻🧍 🧍♀ 🧍 🏻 ♀
  • 70.
    Monoid trait Monoid[A] { defempty: A def combine(a: A, b: A): A } object Monoid { def apply[A](implicit m: Monoid[A]): Monoid[A] = m } モノイド
  • 71.
    Monoid trait Monoid[A] { defempty: A def combine(a: A, b: A): A } object Monoid { def apply[A](implicit m: Monoid[A]): Monoid[A] = m } Identity combine(a, empty) == a combine(empty, a ) == a Associativity combine(combine(a, b), c) == combine(a, combine(b, c) Laws モノイド則は単位元と結合律
  • 72.
    Monoid trait Monoid[A] { defempty: A def combine(a: A, b: A): A } object Monoid { def apply[A](implicit m: Monoid[A]): Monoid[A] = m } Eg. empty combinetype Int 1 * Int 0 + String “” concat Boolean true && Boolean false ||
  • 73.
    Functor trait Functor[F[_]] { defmap[A, B](f: A => B): F[A] => F[B] } object Functor { def apply[F[_]](implicit f : Functor[F]) : Functor[F] = f } Higher kinded type ファンクター
  • 74.
    Functor trait Functor[F[_]] { defmap[A, B](f: A => B): F[A] => F[B] } object Functor { def apply[F[_]](implicit f : Functor[F]) : Functor[F] = f } Identity ? composition ? Laws 単位元? 合成律?
  • 75.
    The identity function defidentity[A](a: A): A = a Identity composition ? Laws 恒等関数
  • 76.
    The identity law defidentity[A](a: A): A = a //REMINDER: def map[A, B](f: A => B): F[A] => F[B] map(identity) == identity Identity composition ? Laws 単位元
  • 77.
    trait Function1[-B, +C]{ def apply(b: B): C def compose[A](g: A => B): A => C = a => apply(g(a)) } Identity composition Laws The compose function 合成関数
  • 78.
    trait Function1[-B, +C]{ def apply(b: B): C def compose[A](g: A => B): A => C = a => apply(g(a)) } f: A => B g: B => C h: A => C h = a => g(f(a)) === g compose f f ° g The compose function
  • 79.
    trait Function1[-B, +C]{ def apply(b: B): C def compose[A](g: A => B): A => C = a => apply(g(a)) } //REMINDER: def map[A, B](f: A => B): F[A] => F[B] map(g compose f) == map(g) compose map(f) Laws The composition law Identity composition
  • 80.
    implicit val optionFunctor:Functor[Option] = new Functor[Option] { override def map[A, B](f: A => B): Option[A] => Option[B] = { case None => None case Some(a) => Some(f(a)) } } Example for a Functor instance Functor[Option] ファンクター・インスタンスの例
  • 81.
    implicit val optionFunctor:Functor[Option] = new Functor[Option] { override def map[A, B](f: A => B): Option[A] => Option[B] = { case None => None case Some(a) => Some(f(a)) } } Identity law for: Functor[Option] f: identity f: A => A None => None Some(a) => Some(a) identity Functor[Option] の単位元
  • 82.
    implicit val optionFunctor:Functor[Option] = new Functor[Option] { override def map[A, B](f: A => B): Option[A] => Option[B] = { case None => None case Some(a) => Some(f(a)) } } Composition law for: Functor[Option] Identity Law map(identity)(Some(1)) == Some(1) map(identity)(None) == None def increment(i: Int): Int def toString(i: Int): String map(toString compose increment) == map(toString) compose map(increment) Some(41) Functor[Option] の合成律
  • 83.
    implicit val optionFunctor:Functor[Option] = new Functor[Option] { override def map[A, B](f: A => B): Option[A] => Option[B] = { case None => None case Some(a) => Some(f(a)) } } Composition law for: Functor[Option] Identity Law map(identity)(Some(1)) == Some(1) map(identity)(None) == None def increment(i: Int): Int def toString(i: Int): String map(toString compose increment) == map(toString) compose map(increment) Some(41) Some(“42”)
  • 84.
    implicit val optionFunctor:Functor[Option] = new Functor[Option] { override def map[A, B](f: A => B): Option[A] => Option[B] = { case None => None case Some(a) => Some(f(a)) } } Composition law for: Functor[Option] Identity Law map(identity)(Some(1)) == Some(1) map(identity)(None) == None def increment(i: Int): Int def toString(i: Int): String map(toString compose increment) == map(toString) compose map(increment) Some(41) Some(“42”) Some(“42”)
  • 85.
    Monad trait Monad[F[_]] { defmap[A, B](f: A => B): F[A] => F[B] def flatMap[A, B](f: A => F[B]): F[A] => F[B] } object Monad { def apply[F[_]](implicit m: Monad[F]) : Monad[F] = m } Higher kinded type モナド
  • 86.
    Monad trait Monad[F[_]] { defpoint[A](a: A): F[A] def map[A, B](f: A => B): F[A] => F[B] def flatMap[A, B](f: A => F[B]): F[A] => F[B] } object Monad { def apply[F[_]](implicit m: Monad[F]) : Monad[F] = m } モナド
  • 87.
    Monad trait Monad[F[_]] { defpoint[A](a: A): F[A] def map[A, B](f: A => B): F[A] => F[B] def flatMap[A, B](f: A => F[B]): F[A] => F[B] } object Monad { def apply[F[_]](implicit m: Monad[F]) : Monad[F] = m } Left identity ? Right identity Associativity ? Laws 左単位元 、右単位元 、結合律
  • 88.
    Left identity def increment(a:Int): Option[Int] = Some(a + 1) Some(42).flatMap(a => increment(2)) == increment(2) Left identity Right identity Associativity ? Laws 左単位元
  • 89.
    Right identity Some(42).flatMap(Some(_)) ==Some(42) Left identity Right identity Associativity ? Laws 右単位元
  • 90.
    Associativity def increment(i: Int):Option[Int] = Some(i + 1) def decrement(i: Int): Option[Int] = Some(i - 1) Some(42).flatMap(increment).flatMap(decrement) == Some(42).flatMap(v => increment(v).flatMap(decrement)) Left identity Right identity Associativity Laws 結合律
  • 91.
    Monads in reallife IOモナドのコンテキストで演算する Haskeller
  • 92.
    You can checkoutthe Scala functional programming libraries: ● Cats Github: https://github.com/typelevel/cats doc: https://typelevel.org/cats ● Scalaz: https://github.com/scalaz/scalaz ● Zio Prelude: https://github.com/zio/zio-prelude Talks by: ● John De Goes and Adam Fraser: “Reimagining Functional Type Classes” ● Jakub Kozlowski: “Fantastic Monads and where to find them” Resources 次へのリソース
  • 93.
  • 94.
    CREDITS: This presentationtemplate was created by Slidesgo, including icons by Flaticon, and infographics & images by Freepik THANKS! Please keep this slide for attribution @WiemZin ご清聴ありがとうございました