Skip to content

Instantly share code, notes, and snippets.

@aoiroaoino
Last active September 16, 2019 06:28
Show Gist options
  • Select an option

  • Save aoiroaoino/f017458c29d0b98eeaf239529f04af22 to your computer and use it in GitHub Desktop.

Select an option

Save aoiroaoino/f017458c29d0b98eeaf239529f04af22 to your computer and use it in GitHub Desktop.

Revisions

  1. aoiroaoino revised this gist Sep 16, 2019. 2 changed files with 23 additions and 6 deletions.
    7 changes: 1 addition & 6 deletions a.md
    Original file line number Diff line number Diff line change
    @@ -24,9 +24,4 @@

    - scalaz.IndexedContsT
    - https://github.com/scalaz/scalaz/blob/v7.2.28/core/src/main/scala/scalaz/IndexedContsT.scala


    ### 発表当日の質問

    <img width="1307" alt="スクリーンショット 2019-09-16 15 17 36" src="https://user-images.githubusercontent.com/2589034/64937483-5e941300-d895-11e9-8870-7ae646f8fbef.png">


    22 changes: 22 additions & 0 deletions b.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,22 @@
    ### 発表当日の質問

    <img width="1307" alt="スクリーンショット 2019-09-16 15 17 36" src="https://user-images.githubusercontent.com/2589034/64937483-5e941300-d895-11e9-8870-7ae646f8fbef.png">

    #### Q&A 1

    Q:
    ここでの「継続」と「関数」の違いは何でしょうか?「継続 = その後に計算される計算/処理」だとして、
    Scalaにおいては関数が「継続」を表現するのにちょうど良いので、関数を使って「継続渡し」を説明している、という感じでしょうか?
    A:

    #### Q&A 2

    Q:
    for式で使いたいだけであればモナドにする必要はないと思いますが、モナドにしておく理由はありますか?
    A:

    #### Q&A 3
    Q:
    継続を見て「これはモナドかも?」という直感が働くのはどういった点ですか?
    A:

  2. aoiroaoino revised this gist Sep 16, 2019. 1 changed file with 6 additions and 0 deletions.
    6 changes: 6 additions & 0 deletions a.md
    Original file line number Diff line number Diff line change
    @@ -24,3 +24,9 @@

    - scalaz.IndexedContsT
    - https://github.com/scalaz/scalaz/blob/v7.2.28/core/src/main/scala/scalaz/IndexedContsT.scala


    ### 発表当日の質問

    <img width="1307" alt="スクリーンショット 2019-09-16 15 17 36" src="https://user-images.githubusercontent.com/2589034/64937483-5e941300-d895-11e9-8870-7ae646f8fbef.png">

  3. aoiroaoino revised this gist Sep 15, 2019. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion a.md
    Original file line number Diff line number Diff line change
    @@ -5,7 +5,7 @@

    ### 補足とか

    - 限定継続です。触れてなくて大丈夫...?
    - 限定継続...
    - エラーハンドリングの実用例みたいなもの
    - https://github.com/aoiroaoino/monoton/blob/a4f326bfa0c/core/src/main/scala/monoton/server/Handler.scala

  4. aoiroaoino revised this gist Sep 15, 2019. 1 changed file with 3 additions and 3 deletions.
    6 changes: 3 additions & 3 deletions a.md
    Original file line number Diff line number Diff line change
    @@ -1,15 +1,15 @@
    # 検証環境とか
    ### 検証環境とか

    - Scala 2.13.0 の REPL
    - ScalaCheck 1.14.0

    # 補足とか
    ### 補足とか

    - 限定継続です。触れてなくて大丈夫...?
    - エラーハンドリングの実用例みたいなもの
    - https://github.com/aoiroaoino/monoton/blob/a4f326bfa0c/core/src/main/scala/monoton/server/Handler.scala

    # 参考資料
    ### 参考資料

    (敬称略)

  5. aoiroaoino revised this gist Sep 15, 2019. 1 changed file with 26 additions and 0 deletions.
    26 changes: 26 additions & 0 deletions a.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,26 @@
    # 検証環境とか

    - Scala 2.13.0 の REPL
    - ScalaCheck 1.14.0

    # 補足とか

    - 限定継続です。触れてなくて大丈夫...?
    - エラーハンドリングの実用例みたいなもの
    - https://github.com/aoiroaoino/monoton/blob/a4f326bfa0c/core/src/main/scala/monoton/server/Handler.scala

    # 参考資料

    (敬称略)

    - shift/reset プログラミング入門 - 浅井 健一
    - http://pllab.is.ocha.ac.jp/~asai/cw2011tutorial/main-j.pdf

    - モナドから始めない継続入門 - @cloudear8
    - https://blog.7nobo.me/2018/01/14/01-haskell-continuation.html

    - Loan パターンのネストは継続モナドでシュッと解決できるよという話 - @jwhaco
    - https://qiita.com/jwhaco/items/224113324fd454b8ca77

    - scalaz.IndexedContsT
    - https://github.com/scalaz/scalaz/blob/v7.2.28/core/src/main/scala/scalaz/IndexedContsT.scala
  6. aoiroaoino revised this gist Sep 15, 2019. No changes.
  7. aoiroaoino revised this gist Sep 15, 2019. No changes.
  8. aoiroaoino revised this gist Sep 15, 2019. 1 changed file with 8 additions and 8 deletions.
    16 changes: 8 additions & 8 deletions practice_12_resource.scala
    Original file line number Diff line number Diff line change
    @@ -31,20 +31,20 @@ res140: List[String] = List(Hello, 1, Hello, 2, Hello, 3)
    // ===

    // close() 実行時に println する独自 Releasable を定義
    def releasable(n: String): Using.Releasable[AutoCloseable] =
    def r(n: String): Using.Releasable[AutoCloseable] =
    _.close().tap(_ => println(s"call close() for $n"))

    // Releasable を明示的に渡して実行
    val prog: Cont[List[String], List[String]] = for {
    a <- resource(new BufferedReader(new FileReader("/tmp/file1.txt")))(releasable("file1"))
    b <- resource(new BufferedReader(new FileReader("/tmp/file2.txt")))(releasable("file2"))
    c <- resource(new BufferedReader(new FileReader("/tmp/file3.txt")))(releasable("file3"))
    a <- resource(new BufferedReader(new FileReader("/tmp/file1.txt")))(r("f1"))
    b <- resource(new BufferedReader(new FileReader("/tmp/file2.txt")))(r("f2"))
    c <- resource(new BufferedReader(new FileReader("/tmp/file3.txt")))(r("f3"))
    } yield {
    (lines(a) ++ lines(b) ++ lines(c)).toList
    }

    scala> prog.run(identity)
    call close() for file3
    call close() for file2
    call close() for file1
    res143: List[String] = List(Hello, 1, Hello, 2, Hello, 3)
    call close() for f3
    call close() for f2
    call close() for f1
    res145: List[String] = List(Hello, 1, Hello, 2, Hello, 3)
  9. aoiroaoino revised this gist Sep 15, 2019. 1 changed file with 30 additions and 20 deletions.
    50 changes: 30 additions & 20 deletions practice_12_resource.scala
    Original file line number Diff line number Diff line change
    @@ -1,40 +1,50 @@
    // ===

    def using[A <: AutoCloseable, B](a: => A, n: String)(f: A => B): B =
    try f(a) finally { a.close(); println(s"close: $n") }

    // Scala 2.13.0 より scala.util.Using が入った
    //話を簡略化するため、例外が投げられる resource を使用
    def resource[R, A](resource: R)(body: (R) => A)(implicit releasable: Releasable[R]): A

    //

    // 継続モナドでラップ
    def resource[R, A](a: => A)(implicit releasable: Releasable[A]): Cont[R, A] =
    Cont(ar => Using.resource(a)(ar))

    // ===

    // Using.Magaer
    def lines(reader: BufferedReader): Iterator[String] =
    Iterator.unfold(())(_ => Option(reader.readLine()).map(_ -> ()))

    // Using.Magaer を使わず、しかも for 式で合成できる
    val prog: Cont[List[String], List[String]] = for {
    _ <- Cont.pure[List[String], Unit](())
    a <- resource(new BufferedReader(new FileReader("/tmp/file1.txt")))(releasable("file1"))
    b <- resource(new BufferedReader(new FileReader("/tmp/file2.txt")))(releasable("file2"))
    c <- resource(new BufferedReader(new FileReader("/tmp/file3.txt")))(releasable("file3"))
    a <- resource(new BufferedReader(new FileReader("/tmp/file1.txt")))
    b <- resource(new BufferedReader(new FileReader("/tmp/file2.txt")))
    c <- resource(new BufferedReader(new FileReader("/tmp/file3.txt")))
    } yield {
    def lines(reader: BufferedReader): Iterator[String] =
    Iterator.unfold(())(_ => Option(reader.readLine()).map(_ -> ()))
    (lines(a) ++ lines(b) ++ lines(c)).toList
    }

    def releasable(n: String): Using.Releasable[AutoCloseable] =
    new Using.Releasable[AutoCloseable] {
    def release(resource: AutoCloseable): Unit = {
    println(s"close() call for $n")
    resource.close()
    }
    }
    scala> prog.run(identity)
    res140: List[String] = List(Hello, 1, Hello, 2, Hello, 3)

    prog.run(identity)
    // ===

    // close() 実行時に println する独自 Releasable を定義
    def releasable(n: String): Using.Releasable[AutoCloseable] =
    _.close().tap(_ => println(s"call close() for $n"))

    // ===
    // Releasable を明示的に渡して実行
    val prog: Cont[List[String], List[String]] = for {
    a <- resource(new BufferedReader(new FileReader("/tmp/file1.txt")))(releasable("file1"))
    b <- resource(new BufferedReader(new FileReader("/tmp/file2.txt")))(releasable("file2"))
    c <- resource(new BufferedReader(new FileReader("/tmp/file3.txt")))(releasable("file3"))
    } yield {
    (lines(a) ++ lines(b) ++ lines(c)).toList
    }

    def using[A <: AutoCloseable, B](a: => A, n: String)(f: A => B): B =
    try f(a) finally { a.close(); println(s"close: $n") }
    scala> prog.run(identity)
    call close() for file3
    call close() for file2
    call close() for file1
    res143: List[String] = List(Hello, 1, Hello, 2, Hello, 3)
  10. aoiroaoino revised this gist Sep 15, 2019. 1 changed file with 35 additions and 3 deletions.
    38 changes: 35 additions & 3 deletions practice_12_resource.scala
    Original file line number Diff line number Diff line change
    @@ -1,8 +1,40 @@
    // ===

    // Scala 2.13.0 より Using が入った
    // Scala 2.13.0 より scala.util.Using が入った
    //話を簡略化するため、例外が投げられる resource を使用
    def resource[R, A](resource: R)(body: (R) => A)(implicit releasable: Releasable[R]): A

    def resource[R, A](a: => A)(implicit F: Releasable[A]): Cont[R, A] =
    //

    def resource[R, A](a: => A)(implicit releasable: Releasable[A]): Cont[R, A] =
    Cont(ar => Using.resource(a)(ar))

    // ===
    // ===

    // Using.Magaer
    val prog: Cont[List[String], List[String]] = for {
    _ <- Cont.pure[List[String], Unit](())
    a <- resource(new BufferedReader(new FileReader("/tmp/file1.txt")))(releasable("file1"))
    b <- resource(new BufferedReader(new FileReader("/tmp/file2.txt")))(releasable("file2"))
    c <- resource(new BufferedReader(new FileReader("/tmp/file3.txt")))(releasable("file3"))
    } yield {
    def lines(reader: BufferedReader): Iterator[String] =
    Iterator.unfold(())(_ => Option(reader.readLine()).map(_ -> ()))
    (lines(a) ++ lines(b) ++ lines(c)).toList
    }

    def releasable(n: String): Using.Releasable[AutoCloseable] =
    new Using.Releasable[AutoCloseable] {
    def release(resource: AutoCloseable): Unit = {
    println(s"close() call for $n")
    resource.close()
    }
    }

    prog.run(identity)


    // ===

    def using[A <: AutoCloseable, B](a: => A, n: String)(f: A => B): B =
    try f(a) finally { a.close(); println(s"close: $n") }
  11. aoiroaoino revised this gist Sep 15, 2019. 1 changed file with 1 addition and 0 deletions.
    1 change: 1 addition & 0 deletions practice_13_attention.scala
    Original file line number Diff line number Diff line change
    @@ -54,6 +54,7 @@ val prog: Cont[Unit, Unit] =
    _ <- insert("some data")
    } yield ()

    // めでたく二回実行されてしまいました
    scala> prog.run(identity)
    insert data to database
    insert data to database
  12. aoiroaoino revised this gist Sep 15, 2019. 1 changed file with 22 additions and 0 deletions.
    22 changes: 22 additions & 0 deletions practice_13_attention.scala
    Original file line number Diff line number Diff line change
    @@ -35,3 +35,25 @@ val prog: Cont[Result, List[User]] =

    scala> prog.run(_.mkString(", "))
    res133: Result = query execution error


    // ===

    // 後続の処理をなんとなく二回実行するやつ
    def twice: Cont[Unit, Unit] = Cont { ar => ar(()); ar(()) }

    // 絶対に一回しか実行して欲しくない DB への書き込み
    def insert(s: String): Cont[Unit, Unit] = Cont { ar =>
    println("insert data to database")
    ar(())
    }

    val prog: Cont[Unit, Unit] =
    for {
    _ <- twice
    _ <- insert("some data")
    } yield ()

    scala> prog.run(identity)
    insert data to database
    insert data to database
  13. aoiroaoino revised this gist Sep 15, 2019. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion practice_13_attention.scala
    Original file line number Diff line number Diff line change
    @@ -25,7 +25,7 @@ res132: Result = [foo], [bar]

    // ===

    // 継続の最後の方で例外が投げられた場合
    // 継続の深いところで例外が投げられた場合
    val prog: Cont[Result, List[User]] =
    for {
    users <- findAll()
  14. aoiroaoino revised this gist Sep 15, 2019. 1 changed file with 3 additions and 1 deletion.
    4 changes: 3 additions & 1 deletion practice_13_attention.scala
    Original file line number Diff line number Diff line change
    @@ -13,6 +13,7 @@ def findAll[R](): Cont[Result, List[User]] = Cont { ar =>

    // ===

    // 全て成功する場合
    val prog: Cont[Result, List[User]] =
    for {
    users <- findAll()
    @@ -24,11 +25,12 @@ res132: Result = [foo], [bar]

    // ===

    // 継続の最後の方で例外が投げられた場合
    val prog: Cont[Result, List[User]] =
    for {
    users <- findAll()
    names <- Cont.pure(users.map(n => s"[$n]"))
    _ = 1 / 0
    _ = 1 / 0 // java.lang.ArithmeticException: / by zero
    } yield names

    scala> prog.run(_.mkString(", "))
  15. aoiroaoino revised this gist Sep 15, 2019. 4 changed files with 43 additions and 3 deletions.
    9 changes: 8 additions & 1 deletion practice_12_resource.scala
    Original file line number Diff line number Diff line change
    @@ -1 +1,8 @@
    w
    // ===

    // Scala 2.13.0 より Using が入った

    def resource[R, A](a: => A)(implicit F: Releasable[A]): Cont[R, A] =
    Cont(ar => Using.resource(a)(ar))

    // ===
    35 changes: 35 additions & 0 deletions practice_13_attention.scala
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,35 @@
    // ===

    type User = String
    type Result = String

    def findAll[R](): Cont[Result, List[User]] = Cont { ar =>
    try {
    ar(List("foo", "bar")) // DB への問い合わせは成功したとする
    } catch {
    case _: Throwable => "query execution error"
    }
    }

    // ===

    val prog: Cont[Result, List[User]] =
    for {
    users <- findAll()
    names <- Cont.pure(users.map(n => s"[$n]"))
    } yield names

    scala> prog.run(_.mkString(", "))
    res132: Result = [foo], [bar]

    // ===

    val prog: Cont[Result, List[User]] =
    for {
    users <- findAll()
    names <- Cont.pure(users.map(n => s"[$n]"))
    _ = 1 / 0
    } yield names

    scala> prog.run(_.mkString(", "))
    res133: Result = query execution error
    1 change: 0 additions & 1 deletion tips_11_monad_in_scala
    Original file line number Diff line number Diff line change
    @@ -1 +0,0 @@
    w
    1 change: 0 additions & 1 deletion tips_11_monad_in_scala.scala
    Original file line number Diff line number Diff line change
    @@ -1 +0,0 @@
    w
  16. aoiroaoino revised this gist Sep 15, 2019. 1 changed file with 2 additions and 4 deletions.
    6 changes: 2 additions & 4 deletions intro_22_cont_monad_law.scala
    Original file line number Diff line number Diff line change
    @@ -48,10 +48,8 @@ class ContMonadSpec extends Properties("Monad[Cont[R, ?]]") {
    // ===

    sbt:check_cont_monad_law> test
    [info] Compiling 1 Scala source to /Users/aoiroaoino/work/check_cont_monad_law/target/scala-2.13/test-classes ...
    [info] Done compiling.
    [info] + Monad[Cont[R, ?]].leftIdentity: OK, passed 100 tests.
    [info] + Monad[Cont[R, ?]].rightIdentity: OK, passed 100 tests.
    [info] + Monad[Cont[R, ?]].leftIdentity: OK, passed 100 tests.
    [info] + Monad[Cont[R, ?]].associativity: OK, passed 100 tests.
    [info] Passed: Total 3, Failed 0, Errors 0, Passed 3
    [success] Total time: 1 s, completed 2019/09/15 19:42:15
    [success] Total time: 1 s, completed 2019/09/15 19:49:36
  17. aoiroaoino revised this gist Sep 15, 2019. 1 changed file with 11 additions and 11 deletions.
    22 changes: 11 additions & 11 deletions intro_22_cont_monad_law.scala
    Original file line number Diff line number Diff line change
    @@ -29,29 +29,29 @@ object Cont {

    class ContMonadSpec extends Properties("Monad[Cont[R, ?]]") {

    def add[R](i: Int, j: Int): Cont[Int, Int] = Cont(_(i + j))
    def show[R](i: Int): Cont[String, String] = Cont(_(s"num: $i"))
    def inc(i: Int): Cont[Int, Int] = Cont(_(i + 1))
    def add_![R](s: String): Cont[String, String] = Cont(_(s + "!"))
    def add_?[R](s: String): Cont[String, String] = Cont(_(s + "?"))

    def exclamation[R](s: String): Cont[String, String] = Cont(_(s + "!"))
    def question[R](s: String): Cont[String, String] = Cont(_(s + "?"))

    property("rightIdentity") = Prop.forAll { (i: Int, j: Int) =>
    add(i, j).flatMap(Cont.pure).run(identity) == add(i, j).run(identity)
    property("rightIdentity") = Prop.forAll { i: Int =>
    inc(i).flatMap(Cont.pure).run(identity) == inc(i).run(identity)
    }
    property("leftIdentity") = Prop.forAll { i: Int =>
    Cont.pure[String, Int](i).flatMap(show).run(identity) == show(i).run(identity)
    Cont.pure[Int, Int](i).flatMap(inc).run(identity) == inc(i).run(identity)
    }
    property("associativity") = Prop.forAll { s: String =>
    Cont.pure(s).flatMap(exclamation).flatMap(question).run(identity) ==
    Cont.pure(s).flatMap(a => exclamation(a).flatMap(question)).run(identity)
    Cont.pure(s).flatMap(add_!).flatMap(add_?).run(identity) ==
    Cont.pure(s).flatMap(a => add_!(a).flatMap(add_?)).run(identity)
    }
    }

    // ===

    sbt:check_cont_monad_law> test
    [info] Compiling 1 Scala source to /Users/aoiroaoino/work/check_cont_monad_law/target/scala-2.13/test-classes ...
    [info] Done compiling.
    [info] + Monad[Cont[R, ?]].leftIdentity: OK, passed 100 tests.
    [info] + Monad[Cont[R, ?]].rightIdentity: OK, passed 100 tests.
    [info] + Monad[Cont[R, ?]].associativity: OK, passed 100 tests.
    [info] Passed: Total 3, Failed 0, Errors 0, Passed 3
    [success] Total time: 0 s, completed 2019/09/15 19:34:12
    [success] Total time: 1 s, completed 2019/09/15 19:42:15
  18. aoiroaoino revised this gist Sep 15, 2019. 1 changed file with 57 additions and 1 deletion.
    58 changes: 57 additions & 1 deletion intro_22_cont_monad_law.scala
    Original file line number Diff line number Diff line change
    @@ -1 +1,57 @@
    wip
    // ===
    sbt.version=1.2.8

    ThisBuild / scalaVersion := "2.13.0"
    ThisBuild / version := "0.1.0-SNAPSHOT"
    ThisBuild / organization := "com.example"
    ThisBuild / organizationName := "example"

    lazy val root = (project in file("."))
    .settings(
    name := "check_cont_monad_law",
    libraryDependencies += "org.scalacheck" %% "scalacheck" % "1.14.0" % Test
    )

    // ===

    package example

    import org.scalacheck.{Prop, Properties}

    final case class Cont[R, A](run: (A => R) => R) {
    def map[B](f: A => B): Cont[R, B] = Cont(br => run(f andThen br))
    def flatMap[B](f: A => Cont[R, B]): Cont[R, B] =
    Cont(br => run(f(_).run(br)))
    }
    object Cont {
    def pure[R, A](a: A): Cont[R, A] = Cont(_(a))
    }

    class ContMonadSpec extends Properties("Monad[Cont[R, ?]]") {

    def add[R](i: Int, j: Int): Cont[Int, Int] = Cont(_(i + j))
    def show[R](i: Int): Cont[String, String] = Cont(_(s"num: $i"))

    def exclamation[R](s: String): Cont[String, String] = Cont(_(s + "!"))
    def question[R](s: String): Cont[String, String] = Cont(_(s + "?"))

    property("rightIdentity") = Prop.forAll { (i: Int, j: Int) =>
    add(i, j).flatMap(Cont.pure).run(identity) == add(i, j).run(identity)
    }
    property("leftIdentity") = Prop.forAll { i: Int =>
    Cont.pure[String, Int](i).flatMap(show).run(identity) == show(i).run(identity)
    }
    property("associativity") = Prop.forAll { s: String =>
    Cont.pure(s).flatMap(exclamation).flatMap(question).run(identity) ==
    Cont.pure(s).flatMap(a => exclamation(a).flatMap(question)).run(identity)
    }
    }

    // ===

    sbt:check_cont_monad_law> test
    [info] + Monad[Cont[R, ?]].leftIdentity: OK, passed 100 tests.
    [info] + Monad[Cont[R, ?]].rightIdentity: OK, passed 100 tests.
    [info] + Monad[Cont[R, ?]].associativity: OK, passed 100 tests.
    [info] Passed: Total 3, Failed 0, Errors 0, Passed 3
    [success] Total time: 0 s, completed 2019/09/15 19:34:12
  19. aoiroaoino revised this gist Sep 15, 2019. 2 changed files with 1 addition and 0 deletions.
    File renamed without changes.
    1 change: 1 addition & 0 deletions tips_11_monad_in_scala.scala
    Original file line number Diff line number Diff line change
    @@ -0,0 +1 @@
    w
  20. aoiroaoino revised this gist Sep 15, 2019. 1 changed file with 12 additions and 1 deletion.
    13 changes: 12 additions & 1 deletion tips_10_monad
    Original file line number Diff line number Diff line change
    @@ -1 +1,12 @@
    w
    // M[_] はモナドの型
    def pure[A](a: A): M[A]
    def flatMap[B](f: A => M[B]): M[B]

    // 右単位元
    fa.flatMap(a => pure(a)) == fa

    // 左単位元
    pure(a).flatMap(f) == f(a)

    // 結合律
    fa.flatMap(f).flatMap(g) == fa.flatMap(a => f(a).flatMap(g))
  21. aoiroaoino revised this gist Sep 14, 2019. 1 changed file with 5 additions and 5 deletions.
    10 changes: 5 additions & 5 deletions practice_11_error_handling.scala
    Original file line number Diff line number Diff line change
    @@ -11,8 +11,8 @@ def successValueOr[R, A](fa: Try[A])(ifFailure: Throwable => R): Cont[R, A] =
    // input から指定された key に対応する値を取り出し、数値型に変換する
    def parseInt(input: Map[String, String], key: String): Cont[String, Int] =
    for {
    s <- someValueOr(input.get(key))("not found")
    i <- successValueOr(Try(s.toInt))(_.getMessage)
    s <- someValueOr(input.get(key))(s"not found: $key")
    i <- successValueOr(Try(s.toInt))(_.toString)
    } yield i

    // ===
    @@ -27,10 +27,10 @@ parseInt(input, "age").run(i => s"result: $i")
    // ===

    scala> parseInt(input, "address").run(i => s"result: $i")
    res95: String = not found
    res99: String = not found: address

    scala> parseInt(input, "name").run(i => s"result: $i")
    res96: String = For input string: "aoiroaoino"
    res100: String = java.lang.NumberFormatException: For input string: "aoiroaoino"

    scala> parseInt(input, "age").run(i => s"result: $i")
    res97: String = result: 17
    res101: String = result: 17
  22. aoiroaoino revised this gist Sep 14, 2019. 1 changed file with 14 additions and 8 deletions.
    22 changes: 14 additions & 8 deletions practice_11_error_handling.scala
    Original file line number Diff line number Diff line change
    @@ -17,14 +17,20 @@ def parseInt(input: Map[String, String], key: String): Cont[String, Int] =

    // ===

    scala> val source = Map("name" -> "aoiroaoino", "age" -> "29")
    source: scala.collection.immutable.Map[String,String] = Map(name -> aoiroaoino, age -> 29)
    // 例えば下記のような input を仮定する
    val input = Map("name" -> "aoiroaoino", "age" -> "17")

    scala> parseInt(source, "address").run(i => s"result: $i")
    res92: String = not found
    parseInt(input, "address").run(i => s"result: $i")
    parseInt(input, "name").run(i => s"result: $i")
    parseInt(input, "age").run(i => s"result: $i")

    scala> parseInt(source, "name").run(i => s"result: $i")
    res93: String = For input string: "aoiroaoino"
    // ===

    scala> parseInt(input, "address").run(i => s"result: $i")
    res95: String = not found

    scala> parseInt(input, "name").run(i => s"result: $i")
    res96: String = For input string: "aoiroaoino"

    scala> parseInt(source, "age").run(i => s"result: $i")
    res94: String = result: 29
    scala> parseInt(input, "age").run(i => s"result: $i")
    res97: String = result: 17
  23. aoiroaoino revised this gist Sep 14, 2019. 1 changed file with 11 additions and 4 deletions.
    15 changes: 11 additions & 4 deletions practice_11_error_handling.scala
    Original file line number Diff line number Diff line change
    @@ -16,8 +16,15 @@ def parseInt(input: Map[String, String], key: String): Cont[String, Int] =
    } yield i

    // ===
    val source = Map("name" -> "aoiroaoino", "age" -> "29")

    parseInt(source, "address").run(i => s"result: $i")
    parseInt(source, "name").run(i => s"result: $i")
    parseInt(source, "age").run(i => s"result: $i")
    scala> val source = Map("name" -> "aoiroaoino", "age" -> "29")
    source: scala.collection.immutable.Map[String,String] = Map(name -> aoiroaoino, age -> 29)

    scala> parseInt(source, "address").run(i => s"result: $i")
    res92: String = not found

    scala> parseInt(source, "name").run(i => s"result: $i")
    res93: String = For input string: "aoiroaoino"

    scala> parseInt(source, "age").run(i => s"result: $i")
    res94: String = result: 29
  24. aoiroaoino revised this gist Sep 14, 2019. 1 changed file with 3 additions and 0 deletions.
    3 changes: 3 additions & 0 deletions practice_11_error_handling.scala
    Original file line number Diff line number Diff line change
    @@ -1,11 +1,14 @@
    import scala.util.Try

    // Some だったら継続に値を渡して実行。None だったら継続を破棄して ifNone の結果を返す
    def someValueOr[R, A](fa: Option[A])(ifNone: => R): Cont[R, A] =
    Cont(ar => fa.fold(ifNone)(ar)) // Cont(fa.fold(ifNone))

    // Success だったら継続に値を渡して実行。None だったら継続を破棄して ifFailure の結果を返す
    def successValueOr[R, A](fa: Try[A])(ifFailure: Throwable => R): Cont[R, A] =
    Cont(ar => fa.fold(ifFailure, ar)) // Cont(fa.fold(ifFailure, _))

    // input から指定された key に対応する値を取り出し、数値型に変換する
    def parseInt(input: Map[String, String], key: String): Cont[String, Int] =
    for {
    s <- someValueOr(input.get(key))("not found")
  25. aoiroaoino revised this gist Sep 14, 2019. 1 changed file with 11 additions and 0 deletions.
    11 changes: 11 additions & 0 deletions practice_10_cond.scala
    Original file line number Diff line number Diff line change
    @@ -1,5 +1,16 @@
    // fizzbuzz

    def fizzCont(i: Int): Cont[String, Int] = Cont { ar =>
    if (i % 3 == 0) {
    "Fizz" // 継続(ar)を実行しないので計算が "Fizz" で終了する
    } else {
    ar(i) // 継続に i を渡し、残りの処理を実行する
    }
    }


    // ===

    def fizzCont(i: Int): Cont[String, Int] = Cont(ar => if (i % 3 == 0) "Fizz" else ar(i))
    def buzzCont(i: Int): Cont[String, Int] = Cont(ar => if (i % 5 == 0) "Buzz" else ar(i))
    def fizzBuzzCont(i: Int): Cont[String, Int] = Cont(ar => if (i % 15 == 0) "FizzBuzz" else ar(i))
  26. aoiroaoino revised this gist Sep 14, 2019. 2 changed files with 41 additions and 2 deletions.
    22 changes: 21 additions & 1 deletion practice_10_cond.scala
    Original file line number Diff line number Diff line change
    @@ -1 +1,21 @@
    w
    // fizzbuzz

    def fizzCont(i: Int): Cont[String, Int] = Cont(ar => if (i % 3 == 0) "Fizz" else ar(i))
    def buzzCont(i: Int): Cont[String, Int] = Cont(ar => if (i % 5 == 0) "Buzz" else ar(i))
    def fizzBuzzCont(i: Int): Cont[String, Int] = Cont(ar => if (i % 15 == 0) "FizzBuzz" else ar(i))

    def fizzBuzz(i: Int): Cont[String, Int] =
    for {
    a <- fizzBuzzCont(i)
    b <- fizzCont(a)
    c <- buzzCont(b)
    } yield c

    // ===

    scala> LazyList.from(1).map(fizzBuzz(_).run(_.toString)).take(15).toList
    res54: List[String] = List(1, 2, Fizz, 4, Buzz, Fizz, 7, 8, Fizz, Buzz, 11, Fizz, 13, 14, FizzBuzz)

    // ===


    21 changes: 20 additions & 1 deletion practice_11_error_handling.scala
    Original file line number Diff line number Diff line change
    @@ -1 +1,20 @@
    w
    import scala.util.Try

    def someValueOr[R, A](fa: Option[A])(ifNone: => R): Cont[R, A] =
    Cont(ar => fa.fold(ifNone)(ar)) // Cont(fa.fold(ifNone))

    def successValueOr[R, A](fa: Try[A])(ifFailure: Throwable => R): Cont[R, A] =
    Cont(ar => fa.fold(ifFailure, ar)) // Cont(fa.fold(ifFailure, _))

    def parseInt(input: Map[String, String], key: String): Cont[String, Int] =
    for {
    s <- someValueOr(input.get(key))("not found")
    i <- successValueOr(Try(s.toInt))(_.getMessage)
    } yield i

    // ===
    val source = Map("name" -> "aoiroaoino", "age" -> "29")

    parseInt(source, "address").run(i => s"result: $i")
    parseInt(source, "name").run(i => s"result: $i")
    parseInt(source, "age").run(i => s"result: $i")
  27. aoiroaoino revised this gist Sep 14, 2019. 3 changed files with 3 additions and 0 deletions.
    1 change: 1 addition & 0 deletions practice_10_cond.scala
    Original file line number Diff line number Diff line change
    @@ -0,0 +1 @@
    w
    1 change: 1 addition & 0 deletions practice_11_error_handling.scala
    Original file line number Diff line number Diff line change
    @@ -0,0 +1 @@
    w
    1 change: 1 addition & 0 deletions practice_12_resource.scala
    Original file line number Diff line number Diff line change
    @@ -0,0 +1 @@
    w
  28. aoiroaoino revised this gist Sep 14, 2019. 2 changed files with 2 additions and 0 deletions.
    1 change: 1 addition & 0 deletions tips_10_monad
    Original file line number Diff line number Diff line change
    @@ -0,0 +1 @@
    w
    1 change: 1 addition & 0 deletions tips_11_monad_in_scala
    Original file line number Diff line number Diff line change
    @@ -0,0 +1 @@
    w
  29. aoiroaoino revised this gist Sep 14, 2019. 1 changed file with 7 additions and 0 deletions.
    7 changes: 7 additions & 0 deletions intro_23_cont_monad_for_syntax.scala
    Original file line number Diff line number Diff line change
    @@ -15,7 +15,14 @@ def prog[R]: Cont[R, String] =

    // ===

    scala> prog.run(s => s.toList)
    res18: List[Char] = List(N, U, M, :, , 9)

    scala> prog.run(s => s.length)
    res19: Int = 6

    scala> prog.run(s => s)
    res20: String = NUM: 9

    // ===

  30. aoiroaoino revised this gist Sep 14, 2019. 3 changed files with 12 additions and 14 deletions.
    10 changes: 7 additions & 3 deletions intro_11_calc.scala
    Original file line number Diff line number Diff line change
    @@ -1,5 +1,6 @@
    // ===
    def add(i: Int, j: Int): Int = i + j
    def mul(i: Int, j: Int): Int = i * j
    def show(i: Int): String = "num: " + i.toString

    val a = add(1, 2)
    @@ -9,33 +10,36 @@ println(s)

    // ===
    def add(i: Int, j: Int): Int = i + j
    def mul(i: Int, j: Int): Int = i * j
    def show(i: Int): String = "num: " + i.toString

    val a = add(1, 2) // 計算結果

    // ↓ その後の計算
    val b = add(a, 3)
    val b = mul(a, 3)
    val s = show(b)
    println(s)


    // ===
    def add(i: Int, j: Int): Int = i + j
    def mul(i: Int, j: Int): Int = i * j
    def show(i: Int): String = "num: " + i.toString

    val a = add(1, 2)
    val b = add(a, 3) // 計算結果
    val b = mul(a, 3) // 計算結果

    // その後の計算
    val s = show(b)
    println(s)

    // ===
    def add(i: Int, j: Int): Int = i + j
    def mul(i: Int, j: Int): Int = i * j
    def show(i: Int): String = "num: " + i.toString

    val a = add(1, 2)
    val b = add(a, 3)
    val b = mul(a, 3)
    val s = show(b) // 計算結果

    // その後の計算
    4 changes: 2 additions & 2 deletions intro_13_cps_compose.scala
    Original file line number Diff line number Diff line change
    @@ -2,15 +2,15 @@

    // 直接スタイル(再掲)
    val a = add(1, 2)
    val b = add(a, 3)
    val b = mul(a, 3)
    val s = show(b)
    println(s)

    // ===

    // 継続渡しスタイル
    add(1, 2){ a =>
    add(a, 3){ b =>
    mul(a, 3){ b =>
    show(b){ s =>
    println(s)
    }
    12 changes: 3 additions & 9 deletions intro_23_cont_monad_for_syntax.scala
    Original file line number Diff line number Diff line change
    @@ -1,33 +1,27 @@
    // ===

    def add[R](i: Int, j: Int): Cont[R, Int] = Cont(ar => ar(i + j))
    def mul[R](i: Int, j: Int): Cont[R, Int] = Cont(ar => ar(i * j))
    def show[R](i: Int): Cont[R, String] = Cont(ar => ar(s"num: $i"))

    def prog[R]: Cont[R, String] =
    for {
    a <- add(1, 2)
    b <- add(a, 3)
    b <- mul(a, 3)
    s <- show(b)
    } yield {
    s.toUpperCase
    }

    // ===

    scala> prog.run(s => s.toList)
    res15: List[Char] = List(N, U, M, :, , 6)

    scala> prog.run(s => s.length)
    res16: Int = 6

    scala> prog.run(s => s)
    res17: String = NUM: 6

    // ===

    def prog[R]: Cont[R, String] =
    add(1, 2).flatMap { a =>
    add(a, 3).flatMap { b =>
    mul(a, 3).flatMap { b =>
    show(b).map { s =>
    s.toUpperCase
    }