├── answerkey ├── state │ ├── 01.hint.txt │ ├── 03.hint.txt │ ├── 04.hint.txt │ ├── 11.hint.txt │ ├── 05.hint.txt │ ├── 05.answer.scala │ ├── 08.hint.txt │ ├── 02.hint.txt │ ├── 09.hint.txt │ ├── 09.answer.scala │ ├── 06.hint.txt │ ├── 02.answer.scala │ ├── 07.hint.txt │ ├── 08.answer.scala │ ├── 01.answer.scala │ ├── 10.hint.markdown │ ├── 04.answer.scala │ ├── 03.answer.scala │ ├── 06.answer.scala │ ├── 11.answer.scala │ ├── 07.answer.scala │ └── 10.answer.scala ├── laziness │ ├── 01.hint.txt │ ├── 03.hint.txt │ ├── 05.hint.txt │ ├── 07.hint.txt │ ├── 08.hint.txt │ ├── 12.hint.txt │ ├── 13.hint.txt │ ├── 04.hint.txt │ ├── 09.answer.scala │ ├── 14.hint.txt │ ├── 11.hint.txt │ ├── 06.answer.scala │ ├── 06.hint.txt │ ├── 09.hint.txt │ ├── 10.answer.scala │ ├── 10.hint.txt │ ├── 15.hint.txt │ ├── 05.answer.scala │ ├── 11.answer.scala │ ├── 16.hint.txt │ ├── 02.hint.txt │ ├── 04.answer.scala │ ├── 08.answer.scala │ ├── 03.answer.scala │ ├── 15.answer.scala │ ├── 07.answer.scala │ ├── 14.answer.scala │ ├── 02.answer.scala │ ├── 12.answer.scala │ ├── 16.answer.scala │ ├── 01.answer.scala │ └── 13.answer.scala ├── monads │ ├── 05.hint.txt │ ├── 10.hint.txt │ ├── 11.hint.txt │ ├── 15.hint.txt │ ├── 16.hint.txt │ ├── 17.hint.txt │ ├── 18.hint.txt │ ├── 07.hint.txt │ ├── 12.answer.scala │ ├── 08.hint.txt │ ├── 13.hint.txt │ ├── 19.hint.txt │ ├── 08.answer.scala │ ├── 07.answer.scala │ ├── 14.hint.txt │ ├── 04.hint.txt │ ├── 06.hint.txt │ ├── 12.hint.txt │ ├── 01.hint.txt │ ├── 20.hint.txt │ ├── 13.answer.scala │ ├── 03.hint.txt │ ├── 09.hint.txt │ ├── 02.hint.txt │ ├── 04.answer.scala │ ├── 17.answer.scala │ ├── 19.answer.scala │ ├── 10.answer.scala │ ├── 05.answer.scala │ ├── 06.answer.scala │ ├── 11.answer.scala │ ├── 18.answer.scala │ ├── 15.answer.scala │ ├── 03.answer.scala │ ├── 01.answer.scala │ ├── 16.answer.scala │ ├── 09.answer.scala │ ├── 02.answer.scala │ ├── 20.answer.scala │ └── 14.answer.scala ├── monoids │ ├── 01.hint.txt │ ├── 12.hint.txt │ ├── 13.hint.txt │ ├── 14.hint.txt │ ├── 15.hint.txt │ ├── 16.hint.txt │ ├── 17.hint.txt │ ├── 18.hint.txt │ ├── 10.hint.txt │ ├── 07.hint.txt │ ├── 15.answer.scala │ ├── 11.hint.txt │ ├── 05.hint.txt │ ├── 04.hint.txt │ ├── 02.hint.txt │ ├── 05.answer.scala │ ├── 17.answer.scala │ ├── 16.answer.scala │ ├── 03.hint.txt │ ├── 09.hint.txt │ ├── 07.answer.scala │ ├── 08.hint.txt │ ├── 06.hint.txt │ ├── 11.answer.scala │ ├── 03.answer.scala │ ├── 04.answer.scala │ ├── 18.answer.scala │ ├── 01.answer.scala │ ├── 14.answer.scala │ ├── 08.answer.scala │ ├── 06.answer.scala │ ├── 10.answer.scala │ ├── 09.answer.scala │ ├── 02.answer.scala │ ├── 13.answer.scala │ └── 12.answer.scala ├── parsing │ ├── 04.hint.txt │ ├── 05.hint.txt │ ├── 10.hint.txt │ ├── 12.hint.txt │ ├── 13.hint.txt │ ├── 15.hint.txt │ ├── 16.hint.txt │ ├── 03.hint.txt │ ├── 08.hint.txt │ ├── 07.hint.txt │ ├── 12.answer.scala │ ├── 01.hint.txt │ ├── 09.answer.scala │ ├── 10.answer.scala │ ├── 06.hint.txt │ ├── 08.answer.scala │ ├── 17.answer.scala │ ├── 14.answer.scala │ ├── 03.answer.scala │ ├── 04.answer.scala │ ├── 14.hint.txt │ ├── 17.hint.txt │ ├── 11.hint.txt │ ├── 15.answer.scala │ ├── 18.hint.txt │ ├── 02.hint.txt │ ├── 01.answer.scala │ ├── 13.answer.scala │ ├── 11.answer.scala │ ├── 06.answer.scala │ ├── 09.hint.txt │ ├── 07.answer.scala │ ├── 05.answer.scala │ ├── 18.answer.scala │ ├── 02.answer.scala │ └── 16.answer.scala ├── testing │ ├── 02.hint.txt │ ├── 04.hint.txt │ ├── 05.hint.txt │ ├── 06.hint.txt │ ├── 07.hint.txt │ ├── 08.hint.txt │ ├── 09.hint.txt │ ├── 10.hint.txt │ ├── 11.hint.txt │ ├── 14.hint.txt │ ├── 16.hint.txt │ ├── 18.hint.txt │ ├── 20.hint.txt │ ├── 13.hint.txt │ ├── 10.answer.scala │ ├── 12.hint.txt │ ├── 17.hint.txt │ ├── 03.hint.txt │ ├── 20.answer.scala │ ├── 12.answer.scala │ ├── 17.answer.scala │ ├── 07.answer.scala │ ├── 15.answer.scala │ ├── 03.answer.scala │ ├── 01.hint.txt │ ├── 19.hint.txt │ ├── 13.answer.scala │ ├── 02.answer.scala │ ├── 15.hint.txt │ ├── 08.answer.scala │ ├── 18.answer.scala │ ├── 11.answer.scala │ ├── 05.answer.scala │ ├── 06.answer.scala │ ├── 16.answer.scala │ ├── 04.answer.scala │ ├── 14.answer.scala │ ├── 01.answer.scala │ └── 09.answer.scala ├── applicative │ ├── 01.hint.txt │ ├── 11.hint.txt │ ├── 15.hint.txt │ ├── 18.hint.txt │ ├── 08.hint.txt │ ├── 05.hint.txt │ ├── 04.hint.txt │ ├── 19.hint.txt │ ├── 20.hint.txt │ ├── 12.hint.txt │ ├── 02.hint.txt │ ├── 13.hint.txt │ ├── 03.hint.txt │ ├── 06.hint.txt │ ├── 16.answer.scala │ ├── 14.hint.txt │ ├── 17.answer.scala │ ├── 16.hint.txt │ ├── 09.hint.txt │ ├── 17.hint.txt │ ├── 07.hint.txt │ ├── 12.answer.scala │ ├── 10.answer.scala │ ├── 04.answer.scala │ ├── 10.hint.txt │ ├── 18.answer.scala │ ├── 01.answer.scala │ ├── 19.answer.scala │ ├── 05.answer.scala │ ├── 09.answer.scala │ ├── 20.answer.scala │ ├── 08.answer.scala │ ├── 11.answer.scala │ ├── 06.answer.scala │ ├── 03.answer.scala │ ├── 13.answer.scala │ ├── 15.answer.scala │ ├── 02.answer.scala │ ├── 14.answer.scala │ └── 07.answer.scala ├── datastructures │ ├── 01.hint.txt │ ├── 03.hint.txt │ ├── 06.hint.txt │ ├── 09.hint.txt │ ├── 10.hint.txt │ ├── 11.hint.txt │ ├── 12.hint.txt │ ├── 14.hint.txt │ ├── 21.hint.txt │ ├── 22.hint.txt │ ├── 23.hint.txt │ ├── 25.hint.txt │ ├── 26.hint.txt │ ├── 27.hint.txt │ ├── 15.hint.txt │ ├── 02.hint.txt │ ├── 19.hint.txt │ ├── 20.hint.txt │ ├── 28.hint.txt │ ├── 09.answer.scala │ ├── 12.answer.scala │ ├── 16.hint.txt │ ├── 16.answer.scala │ ├── 17.hint.txt │ ├── 18.hint.txt │ ├── 08.hint.txt │ ├── 01.answer.scala │ ├── 21.answer.scala │ ├── 05.hint.txt │ ├── 17.answer.scala │ ├── 25.answer.scala │ ├── 28.answer.scala │ ├── 07.hint.txt │ ├── 20.answer.scala │ ├── 29.hint.txt │ ├── 11.answer.scala │ ├── 27.answer.scala │ ├── 04.hint.txt │ ├── 13.hint.txt │ ├── 14.answer.scala │ ├── 07.answer.scala │ ├── 03.answer.scala │ ├── 26.answer.scala │ ├── 24.hint.txt │ ├── 10.answer.scala │ ├── 23.answer.scala │ ├── 05.answer.scala │ ├── 08.answer.scala │ ├── 02.answer.scala │ ├── 19.answer.scala │ ├── 04.answer.scala │ ├── 22.answer.scala │ ├── 18.answer.scala │ ├── 15.answer.scala │ ├── 06.answer.scala │ ├── 24.answer.scala │ └── 29.answer.scala ├── errorhandling │ ├── 01.hint.txt │ ├── 02.hint.txt │ ├── 08.hint.txt │ ├── 03.hint.txt │ ├── 06.hint.txt │ ├── 02.answer.scala │ ├── 05.hint.txt │ ├── 04.hint.txt │ ├── 03.answer.scala │ ├── 07.hint.txt │ ├── 05.answer.scala │ ├── 07.answer.scala │ ├── 06.answer.scala │ ├── 04.answer.scala │ ├── 08.answer.scala │ └── 01.answer.scala ├── iomonad │ ├── 01.hint.txt │ ├── 03.hint.txt │ ├── 02.hint.txt │ ├── 05.hint.txt │ ├── 04.hint.txt │ ├── 01.answer.scala │ ├── 03.answer.scala │ ├── 02.answer.scala │ ├── 04.answer.scala │ └── 05.answer.scala ├── localeffects │ ├── 01.hint.txt │ ├── 02.hint.txt │ ├── 03.hint.txt │ ├── 01.answer.scala │ ├── 02.answer.scala │ └── 03.answer.scala ├── parallelism │ ├── 04.hint.txt │ ├── 06.hint.txt │ ├── 07.hint.txt │ ├── 09.hint.txt │ ├── 11.hint.txt │ ├── 12.hint.txt │ ├── 13.hint.txt │ ├── 14.hint.txt │ ├── 15.hint.txt │ ├── 16.hint.txt │ ├── 17.hint.txt │ ├── 08.answer.scala │ ├── 01.answer.scala │ ├── 01.hint.txt │ ├── 04.answer.scala │ ├── 02.answer.scala │ ├── 10.hint.txt │ ├── 10.answer.scala │ ├── 05.hint.txt │ ├── 08.hint.txt │ ├── 12.answer.scala │ ├── 07.answer.scala │ ├── 02.hint.txt │ ├── 03.hint.txt │ ├── 06.answer.scala │ ├── 15.answer.scala │ ├── 16.answer.scala │ ├── 14.answer.scala │ ├── 11.answer.scala │ ├── 09.answer.scala │ ├── 17.answer.scala │ ├── 13.answer.scala │ ├── 05.answer.scala │ └── 03.answer.scala ├── streamingio │ ├── 01.hint │ ├── 02.hint.txt │ ├── 04.hint.txt │ ├── 05.hint.txt │ ├── 06.hint.txt │ ├── 07.hint.scala │ ├── 08.hint.txt │ ├── 09.hint.txt │ ├── 10.hint.txt │ ├── 12.hint.txt │ ├── 11.hint.txt │ ├── 03.hint.txt │ ├── 06.answer.scala │ ├── 04.answer.scala │ ├── 12.answer.scala │ ├── 03.answer.scala │ ├── 05.answer.scala │ ├── 01.answer.scala │ ├── 10.answer.scala │ ├── 09.answer.scala │ ├── 02.answer.scala │ ├── 08.answer.scala │ ├── 07.answer.scala │ └── 11.answer.scala └── gettingstarted │ ├── 05.answer.scala │ ├── 04.hint.txt │ ├── 02.hint.txt │ ├── 03.hint.txt │ ├── 05.hint.txt │ ├── 02.answer.scala │ ├── 03.answer.scala │ ├── 01.answer.scala │ ├── 04.answer.scala │ └── 01.hint.txt ├── sbt-launch.jar ├── project ├── lib │ └── nomo.jar ├── master │ ├── fpinscala.book │ └── errorhandling.chapter └── Build.scala ├── sbt ├── sbt.bat ├── sbt.cmd ├── .travis.yml ├── .gitignore ├── exercises └── src │ └── main │ └── scala │ └── fpinscala │ ├── datastructures │ ├── Tree.scala │ └── List.scala │ ├── streamingio │ └── MonadCatch.scala │ ├── testing │ └── Gen.scala │ ├── parsing │ └── Parsers.scala │ ├── iomonad │ ├── package.scala │ └── Task.scala │ ├── errorhandling │ ├── Either.scala │ └── Option.scala │ ├── laziness │ └── Stream.scala │ ├── state │ └── State.scala │ └── monads │ └── Monad.scala ├── answers └── src │ └── main │ └── scala │ └── fpinscala │ ├── streamingio │ ├── Partial.scala │ ├── Eq.scala │ ├── MonadCatch.scala │ └── These.scala │ ├── iomonad │ ├── package.scala │ ├── BindTest.scala │ ├── Throw.scala │ └── Task.scala │ └── parsing │ └── JSON.scala └── LICENSE /answerkey/state/01.hint.txt: -------------------------------------------------------------------------------- 1 | - -------------------------------------------------------------------------------- /answerkey/state/03.hint.txt: -------------------------------------------------------------------------------- 1 | - -------------------------------------------------------------------------------- /answerkey/state/04.hint.txt: -------------------------------------------------------------------------------- 1 | - -------------------------------------------------------------------------------- /answerkey/state/11.hint.txt: -------------------------------------------------------------------------------- 1 | - -------------------------------------------------------------------------------- /answerkey/laziness/01.hint.txt: -------------------------------------------------------------------------------- 1 | - -------------------------------------------------------------------------------- /answerkey/laziness/03.hint.txt: -------------------------------------------------------------------------------- 1 | - -------------------------------------------------------------------------------- /answerkey/laziness/05.hint.txt: -------------------------------------------------------------------------------- 1 | - -------------------------------------------------------------------------------- /answerkey/laziness/07.hint.txt: -------------------------------------------------------------------------------- 1 | - -------------------------------------------------------------------------------- /answerkey/laziness/08.hint.txt: -------------------------------------------------------------------------------- 1 | - -------------------------------------------------------------------------------- /answerkey/laziness/12.hint.txt: -------------------------------------------------------------------------------- 1 | - -------------------------------------------------------------------------------- /answerkey/laziness/13.hint.txt: -------------------------------------------------------------------------------- 1 | - -------------------------------------------------------------------------------- /answerkey/monads/05.hint.txt: -------------------------------------------------------------------------------- 1 | - -------------------------------------------------------------------------------- /answerkey/monads/10.hint.txt: -------------------------------------------------------------------------------- 1 | - -------------------------------------------------------------------------------- /answerkey/monads/11.hint.txt: -------------------------------------------------------------------------------- 1 | - -------------------------------------------------------------------------------- /answerkey/monads/15.hint.txt: -------------------------------------------------------------------------------- 1 | - -------------------------------------------------------------------------------- /answerkey/monads/16.hint.txt: -------------------------------------------------------------------------------- 1 | - -------------------------------------------------------------------------------- /answerkey/monads/17.hint.txt: -------------------------------------------------------------------------------- 1 | - -------------------------------------------------------------------------------- /answerkey/monads/18.hint.txt: -------------------------------------------------------------------------------- 1 | - -------------------------------------------------------------------------------- /answerkey/monoids/01.hint.txt: -------------------------------------------------------------------------------- 1 | - -------------------------------------------------------------------------------- /answerkey/monoids/12.hint.txt: -------------------------------------------------------------------------------- 1 | - -------------------------------------------------------------------------------- /answerkey/monoids/13.hint.txt: -------------------------------------------------------------------------------- 1 | - -------------------------------------------------------------------------------- /answerkey/monoids/14.hint.txt: -------------------------------------------------------------------------------- 1 | - -------------------------------------------------------------------------------- /answerkey/monoids/15.hint.txt: -------------------------------------------------------------------------------- 1 | - -------------------------------------------------------------------------------- /answerkey/monoids/16.hint.txt: -------------------------------------------------------------------------------- 1 | - -------------------------------------------------------------------------------- /answerkey/parsing/04.hint.txt: -------------------------------------------------------------------------------- 1 | - -------------------------------------------------------------------------------- /answerkey/parsing/05.hint.txt: -------------------------------------------------------------------------------- 1 | - -------------------------------------------------------------------------------- /answerkey/parsing/10.hint.txt: -------------------------------------------------------------------------------- 1 | - -------------------------------------------------------------------------------- /answerkey/parsing/12.hint.txt: -------------------------------------------------------------------------------- 1 | - -------------------------------------------------------------------------------- /answerkey/parsing/13.hint.txt: -------------------------------------------------------------------------------- 1 | - -------------------------------------------------------------------------------- /answerkey/parsing/15.hint.txt: -------------------------------------------------------------------------------- 1 | - -------------------------------------------------------------------------------- /answerkey/parsing/16.hint.txt: -------------------------------------------------------------------------------- 1 | - -------------------------------------------------------------------------------- /answerkey/testing/02.hint.txt: -------------------------------------------------------------------------------- 1 | - -------------------------------------------------------------------------------- /answerkey/testing/04.hint.txt: -------------------------------------------------------------------------------- 1 | - -------------------------------------------------------------------------------- /answerkey/testing/05.hint.txt: -------------------------------------------------------------------------------- 1 | - -------------------------------------------------------------------------------- /answerkey/testing/06.hint.txt: -------------------------------------------------------------------------------- 1 | - -------------------------------------------------------------------------------- /answerkey/testing/07.hint.txt: -------------------------------------------------------------------------------- 1 | - -------------------------------------------------------------------------------- /answerkey/testing/08.hint.txt: -------------------------------------------------------------------------------- 1 | - -------------------------------------------------------------------------------- /answerkey/testing/09.hint.txt: -------------------------------------------------------------------------------- 1 | - -------------------------------------------------------------------------------- /answerkey/testing/10.hint.txt: -------------------------------------------------------------------------------- 1 | - -------------------------------------------------------------------------------- /answerkey/testing/11.hint.txt: -------------------------------------------------------------------------------- 1 | - -------------------------------------------------------------------------------- /answerkey/testing/14.hint.txt: -------------------------------------------------------------------------------- 1 | - -------------------------------------------------------------------------------- /answerkey/testing/16.hint.txt: -------------------------------------------------------------------------------- 1 | - -------------------------------------------------------------------------------- /answerkey/testing/18.hint.txt: -------------------------------------------------------------------------------- 1 | - -------------------------------------------------------------------------------- /answerkey/testing/20.hint.txt: -------------------------------------------------------------------------------- 1 | - -------------------------------------------------------------------------------- /answerkey/applicative/01.hint.txt: -------------------------------------------------------------------------------- 1 | - -------------------------------------------------------------------------------- /answerkey/applicative/11.hint.txt: -------------------------------------------------------------------------------- 1 | - -------------------------------------------------------------------------------- /answerkey/applicative/15.hint.txt: -------------------------------------------------------------------------------- 1 | - -------------------------------------------------------------------------------- /answerkey/applicative/18.hint.txt: -------------------------------------------------------------------------------- 1 | - -------------------------------------------------------------------------------- /answerkey/datastructures/01.hint.txt: -------------------------------------------------------------------------------- 1 | - -------------------------------------------------------------------------------- /answerkey/datastructures/03.hint.txt: -------------------------------------------------------------------------------- 1 | - -------------------------------------------------------------------------------- /answerkey/datastructures/06.hint.txt: -------------------------------------------------------------------------------- 1 | - -------------------------------------------------------------------------------- /answerkey/datastructures/09.hint.txt: -------------------------------------------------------------------------------- 1 | - -------------------------------------------------------------------------------- /answerkey/datastructures/10.hint.txt: -------------------------------------------------------------------------------- 1 | - -------------------------------------------------------------------------------- /answerkey/datastructures/11.hint.txt: -------------------------------------------------------------------------------- 1 | - -------------------------------------------------------------------------------- /answerkey/datastructures/12.hint.txt: -------------------------------------------------------------------------------- 1 | - -------------------------------------------------------------------------------- /answerkey/datastructures/14.hint.txt: -------------------------------------------------------------------------------- 1 | - -------------------------------------------------------------------------------- /answerkey/datastructures/21.hint.txt: -------------------------------------------------------------------------------- 1 | - -------------------------------------------------------------------------------- /answerkey/datastructures/22.hint.txt: -------------------------------------------------------------------------------- 1 | - -------------------------------------------------------------------------------- /answerkey/datastructures/23.hint.txt: -------------------------------------------------------------------------------- 1 | - -------------------------------------------------------------------------------- /answerkey/datastructures/25.hint.txt: -------------------------------------------------------------------------------- 1 | - -------------------------------------------------------------------------------- /answerkey/datastructures/26.hint.txt: -------------------------------------------------------------------------------- 1 | - -------------------------------------------------------------------------------- /answerkey/datastructures/27.hint.txt: -------------------------------------------------------------------------------- 1 | - -------------------------------------------------------------------------------- /answerkey/errorhandling/01.hint.txt: -------------------------------------------------------------------------------- 1 | - -------------------------------------------------------------------------------- /answerkey/errorhandling/02.hint.txt: -------------------------------------------------------------------------------- 1 | - -------------------------------------------------------------------------------- /answerkey/errorhandling/08.hint.txt: -------------------------------------------------------------------------------- 1 | - -------------------------------------------------------------------------------- /answerkey/iomonad/01.hint.txt: -------------------------------------------------------------------------------- 1 | - 2 | -------------------------------------------------------------------------------- /answerkey/iomonad/03.hint.txt: -------------------------------------------------------------------------------- 1 | - 2 | -------------------------------------------------------------------------------- /answerkey/localeffects/01.hint.txt: -------------------------------------------------------------------------------- 1 | - -------------------------------------------------------------------------------- /answerkey/localeffects/02.hint.txt: -------------------------------------------------------------------------------- 1 | - -------------------------------------------------------------------------------- /answerkey/localeffects/03.hint.txt: -------------------------------------------------------------------------------- 1 | - -------------------------------------------------------------------------------- /answerkey/monoids/17.hint.txt: -------------------------------------------------------------------------------- 1 | - 2 | -------------------------------------------------------------------------------- /answerkey/parallelism/04.hint.txt: -------------------------------------------------------------------------------- 1 | - -------------------------------------------------------------------------------- /answerkey/parallelism/06.hint.txt: -------------------------------------------------------------------------------- 1 | - -------------------------------------------------------------------------------- /answerkey/parallelism/07.hint.txt: -------------------------------------------------------------------------------- 1 | - -------------------------------------------------------------------------------- /answerkey/parallelism/09.hint.txt: -------------------------------------------------------------------------------- 1 | - -------------------------------------------------------------------------------- /answerkey/parallelism/11.hint.txt: -------------------------------------------------------------------------------- 1 | - -------------------------------------------------------------------------------- /answerkey/parallelism/12.hint.txt: -------------------------------------------------------------------------------- 1 | - -------------------------------------------------------------------------------- /answerkey/parallelism/13.hint.txt: -------------------------------------------------------------------------------- 1 | - -------------------------------------------------------------------------------- /answerkey/parallelism/14.hint.txt: -------------------------------------------------------------------------------- 1 | - -------------------------------------------------------------------------------- /answerkey/parallelism/15.hint.txt: -------------------------------------------------------------------------------- 1 | - -------------------------------------------------------------------------------- /answerkey/parallelism/16.hint.txt: -------------------------------------------------------------------------------- 1 | - -------------------------------------------------------------------------------- /answerkey/parallelism/17.hint.txt: -------------------------------------------------------------------------------- 1 | - -------------------------------------------------------------------------------- /answerkey/parsing/03.hint.txt: -------------------------------------------------------------------------------- 1 | - 2 | -------------------------------------------------------------------------------- /answerkey/parsing/08.hint.txt: -------------------------------------------------------------------------------- 1 | - 2 | -------------------------------------------------------------------------------- /answerkey/streamingio/01.hint: -------------------------------------------------------------------------------- 1 | - 2 | -------------------------------------------------------------------------------- /answerkey/streamingio/02.hint.txt: -------------------------------------------------------------------------------- 1 | - 2 | -------------------------------------------------------------------------------- /answerkey/streamingio/04.hint.txt: -------------------------------------------------------------------------------- 1 | - 2 | -------------------------------------------------------------------------------- /answerkey/streamingio/05.hint.txt: -------------------------------------------------------------------------------- 1 | - 2 | -------------------------------------------------------------------------------- /answerkey/streamingio/06.hint.txt: -------------------------------------------------------------------------------- 1 | - 2 | -------------------------------------------------------------------------------- /answerkey/streamingio/07.hint.scala: -------------------------------------------------------------------------------- 1 | - 2 | -------------------------------------------------------------------------------- /answerkey/streamingio/08.hint.txt: -------------------------------------------------------------------------------- 1 | - 2 | -------------------------------------------------------------------------------- /answerkey/streamingio/09.hint.txt: -------------------------------------------------------------------------------- 1 | - 2 | -------------------------------------------------------------------------------- /answerkey/streamingio/10.hint.txt: -------------------------------------------------------------------------------- 1 | - 2 | -------------------------------------------------------------------------------- /answerkey/streamingio/12.hint.txt: -------------------------------------------------------------------------------- 1 | - 2 | -------------------------------------------------------------------------------- /answerkey/laziness/04.hint.txt: -------------------------------------------------------------------------------- 1 | Use `foldRight`. -------------------------------------------------------------------------------- /answerkey/applicative/08.hint.txt: -------------------------------------------------------------------------------- 1 | Follow the types. -------------------------------------------------------------------------------- /answerkey/datastructures/15.hint.txt: -------------------------------------------------------------------------------- 1 | Use `foldRight`. -------------------------------------------------------------------------------- /answerkey/streamingio/11.hint.txt: -------------------------------------------------------------------------------- 1 | Use 'await' 2 | -------------------------------------------------------------------------------- /answerkey/parsing/07.hint.txt: -------------------------------------------------------------------------------- 1 | Use `flatMap` and `succeed`. -------------------------------------------------------------------------------- /answerkey/parsing/12.answer.scala: -------------------------------------------------------------------------------- 1 | Keep reading for a discussion -------------------------------------------------------------------------------- /answerkey/testing/13.hint.txt: -------------------------------------------------------------------------------- 1 | You can use a sized generator. -------------------------------------------------------------------------------- /answerkey/datastructures/02.hint.txt: -------------------------------------------------------------------------------- 1 | Try pattern matching on `l`. -------------------------------------------------------------------------------- /answerkey/datastructures/19.hint.txt: -------------------------------------------------------------------------------- 1 | Again, try using `foldRight`! -------------------------------------------------------------------------------- /answerkey/monoids/18.hint.txt: -------------------------------------------------------------------------------- 1 | Use `mapMergeMonoid` and `intAddition`. -------------------------------------------------------------------------------- /answerkey/parsing/01.hint.txt: -------------------------------------------------------------------------------- 1 | Try mapping over the result of `product`. -------------------------------------------------------------------------------- /answerkey/testing/10.answer.scala: -------------------------------------------------------------------------------- 1 | def unsized: SGen[A] = SGen(_ => this) -------------------------------------------------------------------------------- /answerkey/testing/12.hint.txt: -------------------------------------------------------------------------------- 1 | Use the `listOfN` function you wrote before. -------------------------------------------------------------------------------- /answerkey/parsing/09.answer.scala: -------------------------------------------------------------------------------- 1 | See full implementation in JSON.scala 2 | -------------------------------------------------------------------------------- /answerkey/applicative/05.hint.txt: -------------------------------------------------------------------------------- 1 | You can write `flatMap` using pattern matching. -------------------------------------------------------------------------------- /answerkey/errorhandling/03.hint.txt: -------------------------------------------------------------------------------- 1 | Use the `flatMap` and possibly `map` methods. -------------------------------------------------------------------------------- /answerkey/monoids/10.hint.txt: -------------------------------------------------------------------------------- 1 | A `Stub` should never contain any whitespace. 2 | -------------------------------------------------------------------------------- /sbt-launch.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biubiu/fpinscala/master/sbt-launch.jar -------------------------------------------------------------------------------- /answerkey/applicative/04.hint.txt: -------------------------------------------------------------------------------- 1 | Try it yourself in the REPL with some small examples. -------------------------------------------------------------------------------- /answerkey/monads/07.hint.txt: -------------------------------------------------------------------------------- 1 | Follow the types. There is only one possible implementation. -------------------------------------------------------------------------------- /answerkey/monads/12.answer.scala: -------------------------------------------------------------------------------- 1 | def join[A](mma: F[F[A]]): F[A] = flatMap(mma)(ma => ma) -------------------------------------------------------------------------------- /answerkey/testing/17.hint.txt: -------------------------------------------------------------------------------- 1 | Use the `Gen[Par[Int]]` generator from the last exercise. -------------------------------------------------------------------------------- /answerkey/laziness/09.answer.scala: -------------------------------------------------------------------------------- 1 | def from(n: Int): Stream[Int] = 2 | cons(n, from(n+1)) -------------------------------------------------------------------------------- /answerkey/monoids/07.hint.txt: -------------------------------------------------------------------------------- 1 | The sequences of lengths 0 and 1 are special cases to consider. -------------------------------------------------------------------------------- /answerkey/parsing/10.answer.scala: -------------------------------------------------------------------------------- 1 | The next section works through a possible design in detail. -------------------------------------------------------------------------------- /answerkey/testing/03.hint.txt: -------------------------------------------------------------------------------- 1 | We can refer to the enclosing `Prop` instance with `Prop.this` -------------------------------------------------------------------------------- /answerkey/applicative/19.hint.txt: -------------------------------------------------------------------------------- 1 | Follow the types. There is only implementation that typechecks. -------------------------------------------------------------------------------- /answerkey/applicative/20.hint.txt: -------------------------------------------------------------------------------- 1 | Follow the types. There is only implementation that typechecks. -------------------------------------------------------------------------------- /answerkey/datastructures/20.hint.txt: -------------------------------------------------------------------------------- 1 | You should be able to use a combination of existing functions. -------------------------------------------------------------------------------- /answerkey/laziness/14.hint.txt: -------------------------------------------------------------------------------- 1 | Try to avoid using explicit recursion. Use `zipAll` and `takeWhile`. -------------------------------------------------------------------------------- /answerkey/monads/08.hint.txt: -------------------------------------------------------------------------------- 1 | Look at the signature of `compose`. What happens if `A` is `Unit`? -------------------------------------------------------------------------------- /answerkey/parallelism/08.answer.scala: -------------------------------------------------------------------------------- 1 | Keep reading. The issue is explained in the next paragraph. -------------------------------------------------------------------------------- /answerkey/state/05.hint.txt: -------------------------------------------------------------------------------- 1 | This is an application of `map` over `nonNegativeInt` or `nextInt`. -------------------------------------------------------------------------------- /answerkey/testing/20.answer.scala: -------------------------------------------------------------------------------- 1 | This is an open-ended exercise and we don't give an answer here. -------------------------------------------------------------------------------- /project/lib/nomo.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biubiu/fpinscala/master/project/lib/nomo.jar -------------------------------------------------------------------------------- /answerkey/datastructures/28.hint.txt: -------------------------------------------------------------------------------- 1 | The signature is `def map[A,B](t: Tree[A])(f: A => B): Tree[B]`. -------------------------------------------------------------------------------- /answerkey/monads/13.hint.txt: -------------------------------------------------------------------------------- 1 | Join is sometimes called "flatten", and `flatMap` "maps and then flattens". -------------------------------------------------------------------------------- /answerkey/monads/19.hint.txt: -------------------------------------------------------------------------------- 1 | What would you expect `getState` to return right after you call `setState`? -------------------------------------------------------------------------------- /answerkey/parallelism/01.answer.scala: -------------------------------------------------------------------------------- 1 | /* def map2[A,B,C](a: Par[A], b: Par[B])(f: (A,B) => C): Par[C] */ -------------------------------------------------------------------------------- /sbt: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | java -Xmx1024M -Xss8m -XX:PermSize=300m -jar `dirname $0`/sbt-launch.jar "$@" 3 | -------------------------------------------------------------------------------- /sbt.bat: -------------------------------------------------------------------------------- 1 | set SCRIPT_DIR=%~dp0 2 | java -Xmx512M -Xss8m -jar "%SCRIPT_DIR%sbt-launch.jar" %* 3 | 4 | -------------------------------------------------------------------------------- /answerkey/applicative/12.hint.txt: -------------------------------------------------------------------------------- 1 | The standard library lets you treat a `Map` as essentially a list of pairs. -------------------------------------------------------------------------------- /answerkey/iomonad/02.hint.txt: -------------------------------------------------------------------------------- 1 | Pattern this after the TailRec interpreter we gave in the text earlier 2 | -------------------------------------------------------------------------------- /answerkey/laziness/11.hint.txt: -------------------------------------------------------------------------------- 1 | Review the techniques you used in exercise 4.1 for working with `Option`. 2 | -------------------------------------------------------------------------------- /answerkey/monoids/15.answer.scala: -------------------------------------------------------------------------------- 1 | def toList[A](as: F[A]): List[A] = 2 | foldRight(as)(List[A]())(_ :: _) -------------------------------------------------------------------------------- /answerkey/testing/12.answer.scala: -------------------------------------------------------------------------------- 1 | def listOf[A](g: Gen[A]): SGen[List[A]] = 2 | SGen(n => g.listOfN(n)) -------------------------------------------------------------------------------- /answerkey/testing/17.answer.scala: -------------------------------------------------------------------------------- 1 | val forkProp = Prop.forAllPar(pint2)(i => equal(Par.fork(i), i)) tag "fork" -------------------------------------------------------------------------------- /answerkey/gettingstarted/05.answer.scala: -------------------------------------------------------------------------------- 1 | def compose[A,B,C](f: B => C, g: A => B): A => C = 2 | a => f(g(a)) -------------------------------------------------------------------------------- /answerkey/laziness/06.answer.scala: -------------------------------------------------------------------------------- 1 | def headOption: Option[A] = 2 | foldRight(None: Option[A])((h,_) => Some(h)) -------------------------------------------------------------------------------- /answerkey/parallelism/01.hint.txt: -------------------------------------------------------------------------------- 1 | The function shouldn't require that the two `Par` inputs have the same type. -------------------------------------------------------------------------------- /answerkey/parallelism/04.answer.scala: -------------------------------------------------------------------------------- 1 | def asyncF[A,B](f: A => B): A => Par[B] = 2 | a => lazyUnit(f(a)) 3 | -------------------------------------------------------------------------------- /answerkey/datastructures/09.answer.scala: -------------------------------------------------------------------------------- 1 | def length[A](l: List[A]): Int = 2 | foldRight(l, 0)((_,acc) => acc + 1) -------------------------------------------------------------------------------- /answerkey/laziness/06.hint.txt: -------------------------------------------------------------------------------- 1 | Let `None: Option[A]` be the first argument to `foldRight`. Follow the types from there. -------------------------------------------------------------------------------- /answerkey/monads/08.answer.scala: -------------------------------------------------------------------------------- 1 | def flatMap[A,B](ma: F[A])(f: A => F[B]): F[B] = 2 | compose((_:Unit) => ma, f)(()) -------------------------------------------------------------------------------- /answerkey/parallelism/02.answer.scala: -------------------------------------------------------------------------------- 1 | /* Keep reading - we choose a representation for `Par` later in the chapter. */ -------------------------------------------------------------------------------- /answerkey/parsing/06.hint.txt: -------------------------------------------------------------------------------- 1 | Given a string of digits, `s`, you can use `s.toInt` to convert that to an `Int`. 2 | -------------------------------------------------------------------------------- /answerkey/parsing/08.answer.scala: -------------------------------------------------------------------------------- 1 | def map[A,B](p: Parser[A])(f: A => B): Parser[B] = p.flatMap(a => succeed(f(a))) 2 | -------------------------------------------------------------------------------- /answerkey/parsing/17.answer.scala: -------------------------------------------------------------------------------- 1 | See a fully worked implementation in `instances/Sliceable.scala` in the answers. 2 | -------------------------------------------------------------------------------- /answerkey/state/05.answer.scala: -------------------------------------------------------------------------------- 1 | val _double: Rand[Double] = 2 | map(nonNegativeInt)(_ / (Int.MaxValue.toDouble + 1)) -------------------------------------------------------------------------------- /answerkey/applicative/02.hint.txt: -------------------------------------------------------------------------------- 1 | To implement `map2` in terms of `apply`, try using `f.curried` and following the types. -------------------------------------------------------------------------------- /answerkey/applicative/13.hint.txt: -------------------------------------------------------------------------------- 1 | Follow the types. There is generally only one sensible implementation that typechecks. -------------------------------------------------------------------------------- /answerkey/laziness/09.hint.txt: -------------------------------------------------------------------------------- 1 | The example function `ones` is recursive, how could you define `from` 2 | recursively? 3 | -------------------------------------------------------------------------------- /answerkey/monads/07.answer.scala: -------------------------------------------------------------------------------- 1 | def compose[A,B,C](f: A => F[B], g: B => F[C]): A => F[C] = 2 | a => flatMap(f(a))(g) -------------------------------------------------------------------------------- /answerkey/parallelism/10.hint.txt: -------------------------------------------------------------------------------- 1 | Try adding a second continuation argument to `Future.apply`, which takes an error handler. -------------------------------------------------------------------------------- /answerkey/parsing/14.answer.scala: -------------------------------------------------------------------------------- 1 | Again, see `parsing/instances/Reference.scala` for a fully worked implementation. 2 | -------------------------------------------------------------------------------- /answerkey/streamingio/03.hint.txt: -------------------------------------------------------------------------------- 1 | You'll need to use a local helper function which accepts the current sum and count. 2 | -------------------------------------------------------------------------------- /sbt.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | set SCRIPT_DIR=%~dp0 3 | java %SBT_OPTS% -Xmx512m -Xss8M -jar "%SCRIPT_DIR%sbt-launch.jar" %* 4 | -------------------------------------------------------------------------------- /answerkey/applicative/03.hint.txt: -------------------------------------------------------------------------------- 1 | Look at your implementation of `map2` in terms of `apply` and try to follow the same pattern. -------------------------------------------------------------------------------- /answerkey/datastructures/12.answer.scala: -------------------------------------------------------------------------------- 1 | def reverse[A](l: List[A]): List[A] = foldLeft(l, List[A]())((acc,h) => Cons(h,acc)) -------------------------------------------------------------------------------- /answerkey/datastructures/16.hint.txt: -------------------------------------------------------------------------------- 1 | Try using `foldRight`. You shouldn't need to resort to an explicitly recursive function. -------------------------------------------------------------------------------- /answerkey/monads/14.hint.txt: -------------------------------------------------------------------------------- 1 | Rewrite the monad laws stated in terms of `flatMap` by substituting your implementation of `join`. -------------------------------------------------------------------------------- /answerkey/monoids/11.hint.txt: -------------------------------------------------------------------------------- 1 | You can write default implementations on the `Foldable` trait an then `override` them as necessary. -------------------------------------------------------------------------------- /answerkey/parallelism/10.answer.scala: -------------------------------------------------------------------------------- 1 | We give a fully fleshed-out solution in the `Task` data type in the code for Chapter 13. -------------------------------------------------------------------------------- /answerkey/testing/07.answer.scala: -------------------------------------------------------------------------------- 1 | def union[A](g1: Gen[A], g2: Gen[A]): Gen[A] = 2 | boolean.flatMap(b => if (b) g1 else g2) -------------------------------------------------------------------------------- /answerkey/datastructures/16.answer.scala: -------------------------------------------------------------------------------- 1 | def add1(l: List[Int]): List[Int] = 2 | foldRight(l, Nil:List[Int])((h,t) => Cons(h+1,t)) -------------------------------------------------------------------------------- /answerkey/datastructures/17.hint.txt: -------------------------------------------------------------------------------- 1 | Again, try using `foldRight`. You shouldn't need to resort to an explicitly recursive function. -------------------------------------------------------------------------------- /answerkey/datastructures/18.hint.txt: -------------------------------------------------------------------------------- 1 | Again, try using `foldRight`. You shouldn't need to resort to an explicitly recursive function. -------------------------------------------------------------------------------- /answerkey/errorhandling/06.hint.txt: -------------------------------------------------------------------------------- 1 | The `map2` function that we wrote earlier for `Option` will follow the same pattern for `Either`. -------------------------------------------------------------------------------- /answerkey/monoids/05.hint.txt: -------------------------------------------------------------------------------- 1 | You can `map` and then `concatenate`, but that will go over the list twice. Use a single fold instead. -------------------------------------------------------------------------------- /answerkey/state/08.hint.txt: -------------------------------------------------------------------------------- 1 | The implementation using `flatMap` will be almost identical to the failed one where we tried to use `map`. -------------------------------------------------------------------------------- /answerkey/datastructures/08.hint.txt: -------------------------------------------------------------------------------- 1 | The first step in the trace is `Cons(1, foldRight(Cons(2, Cons(3, Nil)), Nil:List[Int])(Cons(_,_)))` -------------------------------------------------------------------------------- /answerkey/parsing/03.answer.scala: -------------------------------------------------------------------------------- 1 | def many[A](p: Parser[A]): Parser[List[A]] = 2 | map2(p, many(p))(_ :: _) or succeed(List()) 3 | 4 | -------------------------------------------------------------------------------- /answerkey/datastructures/01.answer.scala: -------------------------------------------------------------------------------- 1 | /* 2 | 3. The third case is the first that matches, with `x` bound to 1 and `y` bound to 2. 3 | */ -------------------------------------------------------------------------------- /answerkey/monads/04.hint.txt: -------------------------------------------------------------------------------- 1 | There is more than one way of writing this function. For example, try starting with a `List[F[A]]` of length `n`. -------------------------------------------------------------------------------- /answerkey/monads/06.hint.txt: -------------------------------------------------------------------------------- 1 | You can start by pattern matching on the argument. If the list is empty, our only choice is to return `unit(Nil)` -------------------------------------------------------------------------------- /answerkey/monads/12.hint.txt: -------------------------------------------------------------------------------- 1 | Follow the types here. Remember that `A` can be _any type at all_, including the type `F[B]` for some type `B`. -------------------------------------------------------------------------------- /answerkey/applicative/06.hint.txt: -------------------------------------------------------------------------------- 1 | Implement `map2` using pattern matching. If both sides are a failure, try to keep the order of failures consistent. -------------------------------------------------------------------------------- /answerkey/applicative/16.answer.scala: -------------------------------------------------------------------------------- 1 | def reverse[A](fa: F[A]): F[A] = 2 | mapAccum(fa, toList(fa).reverse)((_, as) => (as.head, as.tail))._1 3 | -------------------------------------------------------------------------------- /answerkey/laziness/10.answer.scala: -------------------------------------------------------------------------------- 1 | val fibs = { 2 | def go(f0: Int, f1: Int): Stream[Int] = 3 | cons(f0, go(f1, f0+f1)) 4 | go(0, 1) 5 | } -------------------------------------------------------------------------------- /answerkey/testing/15.answer.scala: -------------------------------------------------------------------------------- 1 | /* A detailed answer is to be found in the file Exhaustive.scala in the code 2 | accompanying this chapter. */ -------------------------------------------------------------------------------- /answerkey/applicative/14.hint.txt: -------------------------------------------------------------------------------- 1 | What happens if you call `traverse` with `Applicative[Option]`? Is there an even simpler `Applicative` you could use? -------------------------------------------------------------------------------- /answerkey/applicative/17.answer.scala: -------------------------------------------------------------------------------- 1 | override def foldLeft[A,B](fa: F[A])(z: B)(f: (B, A) => B): B = 2 | mapAccum(fa, z)((a, b) => ((), f(b, a)))._2 -------------------------------------------------------------------------------- /answerkey/datastructures/21.answer.scala: -------------------------------------------------------------------------------- 1 | def filterViaFlatMap[A](l: List[A])(f: A => Boolean): List[A] = 2 | flatMap(l)(a => if (f(a)) List(a) else Nil) -------------------------------------------------------------------------------- /answerkey/laziness/10.hint.txt: -------------------------------------------------------------------------------- 1 | Chapter two discussed writing loops functionally, using a recursive 2 | helper function - how would that apply here? 3 | -------------------------------------------------------------------------------- /answerkey/parallelism/05.hint.txt: -------------------------------------------------------------------------------- 1 | One possible implementation will be very similar in structure to a function we've implemented previously, for `Option`. -------------------------------------------------------------------------------- /answerkey/parallelism/08.hint.txt: -------------------------------------------------------------------------------- 1 | There is a problem is with fixed size thread pools. What happens if the thread pool is bounded to be of exactly size 1? -------------------------------------------------------------------------------- /answerkey/datastructures/05.hint.txt: -------------------------------------------------------------------------------- 1 | What should the function do if the list is empty? 2 | What if it's not empty? 3 | Use pattern-matching and recursion. 4 | -------------------------------------------------------------------------------- /answerkey/datastructures/17.answer.scala: -------------------------------------------------------------------------------- 1 | def doubleToString(l: List[Double]): List[String] = 2 | foldRight(l, Nil:List[String])((h,t) => Cons(h.toString,t)) -------------------------------------------------------------------------------- /answerkey/datastructures/25.answer.scala: -------------------------------------------------------------------------------- 1 | def size[A](t: Tree[A]): Int = t match { 2 | case Leaf(_) => 1 3 | case Branch(l,r) => 1 + size(l) + size(r) 4 | } -------------------------------------------------------------------------------- /answerkey/errorhandling/02.answer.scala: -------------------------------------------------------------------------------- 1 | def variance(xs: Seq[Double]): Option[Double] = 2 | mean(xs) flatMap (m => mean(xs.map(x => math.pow(x - m, 2)))) -------------------------------------------------------------------------------- /answerkey/laziness/15.hint.txt: -------------------------------------------------------------------------------- 1 | Try `unfold` with `this` as the starting state. You may want to handle emitting the empty `Stream` at the end as a special case. -------------------------------------------------------------------------------- /answerkey/monoids/04.hint.txt: -------------------------------------------------------------------------------- 1 | You will need to generate three values of type `A` for testing associativity. Write a new `Gen` combinator for this if necessary. -------------------------------------------------------------------------------- /answerkey/monads/01.hint.txt: -------------------------------------------------------------------------------- 1 | You have already defined `unit` and `flatMap` for these types. The solution is to simply call them from your `Monad` implementation. -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: scala 2 | sudo: false 3 | scala: 4 | - 2.11.5 5 | jdk: 6 | - oraclejdk7 7 | - openjdk7 8 | notifications: 9 | email: false 10 | -------------------------------------------------------------------------------- /answerkey/applicative/16.hint.txt: -------------------------------------------------------------------------------- 1 | We need to use a stack. Fortunately a `List` is the same thing as a stack, and we already know how to turn any traversable into a list! -------------------------------------------------------------------------------- /answerkey/gettingstarted/04.hint.txt: -------------------------------------------------------------------------------- 1 | You want to return a binary function, so start by taking two arguments. You will have to pass those arguments to `f` one at a time. -------------------------------------------------------------------------------- /answerkey/iomonad/05.hint.txt: -------------------------------------------------------------------------------- 1 | Use `Par.async[Either[Throwable,Array[Byte]]] { cb => ... }`. Follow the types - what is the type of `cb` here and how can you use it? 2 | -------------------------------------------------------------------------------- /answerkey/laziness/05.answer.scala: -------------------------------------------------------------------------------- 1 | def takeWhile_1(f: A => Boolean): Stream[A] = 2 | foldRight(empty[A])((h,t) => 3 | if (f(h)) cons(h,t) 4 | else empty) -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.un~ 2 | *.swp 3 | tags 4 | target 5 | project/boot 6 | .history 7 | project.vim 8 | *.old 9 | .idea 10 | .project 11 | .classpath 12 | .metadata/ 13 | -------------------------------------------------------------------------------- /answerkey/parsing/04.answer.scala: -------------------------------------------------------------------------------- 1 | def listOfN[A](n: Int, p: Parser[A]): Parser[List[A]] = 2 | if (n <= 0) succeed(List()) 3 | else map2(p, listOfN(n-1, p))(_ :: _) 4 | -------------------------------------------------------------------------------- /answerkey/parsing/14.hint.txt: -------------------------------------------------------------------------------- 1 | You may want `string` to report the immediate cause of failure (whichever character didn't match), as well as the overall string being parsed. -------------------------------------------------------------------------------- /answerkey/state/02.hint.txt: -------------------------------------------------------------------------------- 1 | Use `nonNegativeInt` to generate a random integer between `0` and `Int.MaxValue`, inclusive. Then map that to the range of doubles from 0 to 1. -------------------------------------------------------------------------------- /answerkey/streamingio/06.answer.scala: -------------------------------------------------------------------------------- 1 | // this uses the `zip` function defined in exercise 7 2 | def zipWithIndex: Process[I,(O,Int)] = 3 | this zip (count map (_ - 1)) 4 | -------------------------------------------------------------------------------- /answerkey/applicative/09.hint.txt: -------------------------------------------------------------------------------- 1 | The definition of `map2` is very short. The only things you can do are `map2` and `unit` from the `F` and `G` applicatives. Follow the types. -------------------------------------------------------------------------------- /answerkey/monads/20.hint.txt: -------------------------------------------------------------------------------- 1 | This monad is very similar to the `State` monad, except that it's "read-only". You can "get" but not "set" the `R` value that `flatMap` carries along. -------------------------------------------------------------------------------- /answerkey/parsing/17.hint.txt: -------------------------------------------------------------------------------- 1 | Try adding another piece of state to `Location`, `isSliced`. You may want to rename `Location` to `ParseState`, as it's no longer just the location! -------------------------------------------------------------------------------- /answerkey/applicative/17.hint.txt: -------------------------------------------------------------------------------- 1 | This implementation is very similar to `toList` except instead of accumulating into a list, we are accumulating into a `B` using the `f` function. -------------------------------------------------------------------------------- /answerkey/iomonad/04.hint.txt: -------------------------------------------------------------------------------- 1 | To define translate, use `runFree` with `Free[Function0,_]` as the target monad. Then use the specialized `runTrampoline` function written earlier. 2 | -------------------------------------------------------------------------------- /answerkey/localeffects/01.answer.scala: -------------------------------------------------------------------------------- 1 | def fill(xs: Map[Int,A]): ST[S,Unit] = 2 | xs.foldRight(ST[S,Unit](())) { 3 | case ((k, v), st) => st flatMap (_ => write(k, v)) 4 | } -------------------------------------------------------------------------------- /project/master/fpinscala.book: -------------------------------------------------------------------------------- 1 | book fpinscala #[ 2 | part 1 #[ 3 | include errorhandling.chapter 4 | include laziness.chapter 5 | ]# 6 | ]# 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /answerkey/parallelism/12.answer.scala: -------------------------------------------------------------------------------- 1 | def choiceMap[K,V](key: Par[K])(choices: Map[K,Par[V]]): Par[V] = 2 | es => { 3 | val k = run(es)(key).get 4 | run(es)(choices(k)) 5 | } -------------------------------------------------------------------------------- /answerkey/datastructures/28.answer.scala: -------------------------------------------------------------------------------- 1 | def map[A,B](t: Tree[A])(f: A => B): Tree[B] = t match { 2 | case Leaf(a) => Leaf(f(a)) 3 | case Branch(l,r) => Branch(map(l)(f), map(r)(f)) 4 | } -------------------------------------------------------------------------------- /answerkey/state/09.hint.txt: -------------------------------------------------------------------------------- 1 | `_map`- your solution will be similar to `nonNegativeLessThan`. 2 | 3 | `_map2` - your solution to `map2` for the `Option` data type should give you some ideas. 4 | -------------------------------------------------------------------------------- /answerkey/laziness/11.answer.scala: -------------------------------------------------------------------------------- 1 | def unfold[A, S](z: S)(f: S => Option[(A, S)]): Stream[A] = 2 | f(z) match { 3 | case Some((h,s)) => cons(h, unfold(s)(f)) 4 | case None => empty 5 | } -------------------------------------------------------------------------------- /answerkey/laziness/16.hint.txt: -------------------------------------------------------------------------------- 1 | The function can't be implemented using `unfold`, since `unfold` generates elements of the `Stream` from left to right. It can be implemented using `foldRight` though. -------------------------------------------------------------------------------- /answerkey/parallelism/07.answer.scala: -------------------------------------------------------------------------------- 1 | /* 2 | See https://github.com/quchen/articles/blob/master/second_functor_law.md 3 | 4 | Also https://gist.github.com/pchiusano/444de1f222f1ceb09596 5 | */ 6 | -------------------------------------------------------------------------------- /answerkey/parsing/11.hint.txt: -------------------------------------------------------------------------------- 1 | Here are two options: we could return the most recent error in the `or` chain, or we could return whichever error occurred after getting furthest into the input string. -------------------------------------------------------------------------------- /answerkey/parsing/15.answer.scala: -------------------------------------------------------------------------------- 1 | Again see reference implementation here https://github.com/fpinscala/fpinscala/blob/master/answers/src/main/scala/fpinscala/parsing/instances/Reference.scala 2 | -------------------------------------------------------------------------------- /answerkey/parsing/18.hint.txt: -------------------------------------------------------------------------------- 1 | You can add an attribute `otherFailures: List[ParseError]` on `ParseError` itself. This will be a list of parse errors that occurred in other branches of the parser. -------------------------------------------------------------------------------- /answerkey/testing/03.answer.scala: -------------------------------------------------------------------------------- 1 | /* We can refer to the enclosing `Prop` instance with `Prop.this` */ 2 | def &&(p: Prop): Prop = new Prop { 3 | def check = Prop.this.check && p.check 4 | } 5 | -------------------------------------------------------------------------------- /answerkey/datastructures/07.hint.txt: -------------------------------------------------------------------------------- 1 | Look at the program trace from the previous example. Based on the trace, 2 | is it possible the function supplied could choose to terminate the recursion early? 3 | -------------------------------------------------------------------------------- /answerkey/datastructures/20.answer.scala: -------------------------------------------------------------------------------- 1 | /* 2 | This could also be implemented directly using `foldRight`. 3 | */ 4 | def flatMap[A,B](l: List[A])(f: A => List[B]): List[B] = 5 | concat(map(l)(f)) -------------------------------------------------------------------------------- /answerkey/monads/13.answer.scala: -------------------------------------------------------------------------------- 1 | def flatMap[A,B](ma: F[A])(f: A => F[B]) = 2 | join(map(ma)(f)) 3 | 4 | def compose[A,B,C](f: A => F[B], g: B => F[C]): A => F[C] = 5 | a => join(map(f(a))(g)) 6 | -------------------------------------------------------------------------------- /answerkey/monoids/02.hint.txt: -------------------------------------------------------------------------------- 1 | Because we are abstract in the type parameter `A`, we are limited in the number of possible implementations. But there's more than one implementation that meets the monoid laws. -------------------------------------------------------------------------------- /answerkey/streamingio/04.answer.scala: -------------------------------------------------------------------------------- 1 | def sum2: Process[Double,Double] = 2 | loop(0.0)((d:Double, acc) => (acc+d,acc+d)) 3 | 4 | def count3[I]: Process[I,Int] = 5 | loop(0)((_:I,n) => (n+1,n+1)) 6 | 7 | -------------------------------------------------------------------------------- /answerkey/datastructures/29.hint.txt: -------------------------------------------------------------------------------- 1 | The signature is `def fold[A,B](t: Tree[A])(l: A => B)(b: (B,B) => B): B`. See if you can define this function, then reimplement the functions you've already written for `Tree`. -------------------------------------------------------------------------------- /answerkey/gettingstarted/02.hint.txt: -------------------------------------------------------------------------------- 1 | You know the array is not sorted as soon as you encounter two adjacent elements for which `gt(first, second)` 2 | returns true (note that equal adjacent elements are in order). -------------------------------------------------------------------------------- /answerkey/gettingstarted/03.hint.txt: -------------------------------------------------------------------------------- 1 | You have to take an argument of type `A` and return a function of type `B => C`. That function has to take an argument of type `B` and return a value of type `C`. Follow the types. -------------------------------------------------------------------------------- /answerkey/parsing/02.hint.txt: -------------------------------------------------------------------------------- 1 | Multiplication of numbers is associative, `a * (b * c) == (a * b) * c`. Is there an analogous property for parsers? What can you say about the relationship between `map` and `product`? 2 | -------------------------------------------------------------------------------- /answerkey/streamingio/12.answer.scala: -------------------------------------------------------------------------------- 1 | /* Exercise 12: Implement `join`. Notice this is the standard monadic combinator! */ 2 | def join[F[_],A](p: Process[F,Process[F,A]]): Process[F,A] = 3 | p.flatMap(pa => pa) 4 | -------------------------------------------------------------------------------- /answerkey/applicative/07.hint.txt: -------------------------------------------------------------------------------- 1 | Implement `map2` in terms of `flatMap`. Start with each applicative law in turn, then substitute equals for equals and apply the monad laws until you get an equation that is obviously true. -------------------------------------------------------------------------------- /answerkey/applicative/12.answer.scala: -------------------------------------------------------------------------------- 1 | def sequenceMap[K,V](ofa: Map[K,F[V]]): F[Map[K,V]] = 2 | (ofa foldLeft unit(Map.empty[K,V])) { case (acc, (k, fv)) => 3 | map2(acc, fv)((m, v) => m + (k -> v)) 4 | } 5 | -------------------------------------------------------------------------------- /answerkey/errorhandling/05.hint.txt: -------------------------------------------------------------------------------- 1 | The `traverse` function can be written with explicit recursion or use `foldRight` to do the recursion for you. Implementing `sequence` using `traverse` may be more trivial than you think. -------------------------------------------------------------------------------- /answerkey/monads/03.hint.txt: -------------------------------------------------------------------------------- 1 | These implementations should be very similar to implementations from previous chapters, only with more general types, and using the functions on the `Monad` trait. Make use of `unit` and `map2`. -------------------------------------------------------------------------------- /answerkey/monoids/05.answer.scala: -------------------------------------------------------------------------------- 1 | // Notice that this function does not require the use of `map` at all. 2 | def foldMap[A, B](as: List[A], m: Monoid[B])(f: A => B): B = 3 | as.foldLeft(m.zero)((b, a) => m.op(b, f(a))) -------------------------------------------------------------------------------- /answerkey/monoids/17.answer.scala: -------------------------------------------------------------------------------- 1 | def functionMonoid[A,B](B: Monoid[B]): Monoid[A => B] = 2 | new Monoid[A => B] { 3 | def op(f: A => B, g: A => B) = a => B.op(f(a), g(a)) 4 | val zero: A => B = a => B.zero 5 | } -------------------------------------------------------------------------------- /answerkey/datastructures/11.answer.scala: -------------------------------------------------------------------------------- 1 | def sum3(l: List[Int]) = foldLeft(l, 0)(_ + _) 2 | def product3(l: List[Double]) = foldLeft(l, 1.0)(_ * _) 3 | 4 | def length2[A](l: List[A]): Int = foldLeft(l, 0)((acc,h) => acc + 1) -------------------------------------------------------------------------------- /answerkey/errorhandling/04.hint.txt: -------------------------------------------------------------------------------- 1 | Break the list out using pattern-matching where there will be a recursive call to `sequence` in the cons case. Alternatively, use the `foldRight` method to take care of the recursion for you. -------------------------------------------------------------------------------- /answerkey/applicative/10.answer.scala: -------------------------------------------------------------------------------- 1 | // If `self` and `G` both satisfy the laws, then so does the composite. 2 | // The full proof of the laws can be found at: 3 | // https://github.com/runarorama/sannanir/blob/master/Applicative.v -------------------------------------------------------------------------------- /answerkey/parallelism/02.hint.txt: -------------------------------------------------------------------------------- 1 | What if `run` were backed by a `java.util.concurrent.ExecutorService`? You may want to spend some time looking through the `java.util.concurrent` package to see what other useful things you can find. -------------------------------------------------------------------------------- /answerkey/testing/01.hint.txt: -------------------------------------------------------------------------------- 1 | When thinking of properties a function should satisfy, it often helps to consider inputs that have some structure that is easy to describe. A list where all the elements are the same is one simple structure. -------------------------------------------------------------------------------- /answerkey/gettingstarted/05.hint.txt: -------------------------------------------------------------------------------- 1 | You need to return a new function of type `A => C`. Start by accepting an argument of type `A`. Now follow the types. You have an `A`. What can you do with it? Do you have a function that accepts an `A`? -------------------------------------------------------------------------------- /answerkey/state/09.answer.scala: -------------------------------------------------------------------------------- 1 | def _map[A,B](s: Rand[A])(f: A => B): Rand[B] = 2 | flatMap(s)(a => unit(f(a))) 3 | 4 | def _map2[A,B,C](ra: Rand[A], rb: Rand[B])(f: (A, B) => C): Rand[C] = 5 | flatMap(ra)(a => map(rb)(b => f(a, b))) 6 | -------------------------------------------------------------------------------- /answerkey/laziness/02.hint.txt: -------------------------------------------------------------------------------- 1 | Many `Stream` functions can start by pattern matching on the `Stream` and considering what to do in each of the two cases. This particular function needs to first consider whether it needs to look at the stream at all. -------------------------------------------------------------------------------- /answerkey/parsing/01.answer.scala: -------------------------------------------------------------------------------- 1 | def map2[A,B,C](p: Parser[A], p2: Parser[B])( 2 | f: (A,B) => C): Parser[C] = 3 | map(product(p, p2))(f.tupled) 4 | def many1[A](p: Parser[A]): Parser[List[A]] = 5 | map2(p, many(p))(_ :: _) -------------------------------------------------------------------------------- /answerkey/parsing/13.answer.scala: -------------------------------------------------------------------------------- 1 | There is a completed reference implementation of `Parsers` in `parsing/instances/Reference.scala`, though we recommend you continue reading before looking at that, since we're still refining the representation. 2 | -------------------------------------------------------------------------------- /answerkey/state/06.hint.txt: -------------------------------------------------------------------------------- 1 | Start by accepting an RNG. Note that you have a choice in which RNG to pass to which function, and in what order. Think about what you expect the behavior to be, and whether your implementation meets that expectation. -------------------------------------------------------------------------------- /answerkey/testing/19.hint.txt: -------------------------------------------------------------------------------- 1 | If we are just looking at the random case, one way to have the generated `Int` depend on the `String` might be to set the seed of a new random number generator to be equal to the `hashCode` of the given input `String`. -------------------------------------------------------------------------------- /answerkey/monads/09.hint.txt: -------------------------------------------------------------------------------- 1 | You want to show that these two are equivalent: 2 | 3 | flatMap(flatMap(x)(f))(g) == flatMap(x)(a => flatMap(f(a))(g)) 4 | compose(compose(f, g), h) == compose(f, compose(g, h)) 5 | 6 | Rewrite one in terms of the other. -------------------------------------------------------------------------------- /answerkey/datastructures/27.answer.scala: -------------------------------------------------------------------------------- 1 | /* 2 | Again, note how similar the implementation is to `size` and `maximum`. 3 | */ 4 | def depth[A](t: Tree[A]): Int = t match { 5 | case Leaf(_) => 0 6 | case Branch(l,r) => 1 + (depth(l) max depth(r)) 7 | } -------------------------------------------------------------------------------- /answerkey/errorhandling/03.answer.scala: -------------------------------------------------------------------------------- 1 | // a bit later in the chapter we'll learn nicer syntax for 2 | // writing functions like this 3 | def map2[A,B,C](a: Option[A], b: Option[B])(f: (A, B) => C): Option[C] = 4 | a flatMap (aa => b map (bb => f(aa, bb))) -------------------------------------------------------------------------------- /answerkey/laziness/04.answer.scala: -------------------------------------------------------------------------------- 1 | /* 2 | Since `&&` is non-strict in its second argument, this terminates the traversal as soon as a nonmatching element is found. 3 | */ 4 | def forAll(f: A => Boolean): Boolean = 5 | foldRight(true)((a,b) => f(a) && b) -------------------------------------------------------------------------------- /answerkey/monoids/16.answer.scala: -------------------------------------------------------------------------------- 1 | def productMonoid[A,B](A: Monoid[A], B: Monoid[B]): Monoid[(A, B)] = 2 | new Monoid[(A, B)] { 3 | def op(x: (A, B), y: (A, B)) = 4 | (A.op(x._1, y._1), B.op(x._2, y._2)) 5 | val zero = (A.zero, B.zero) 6 | } -------------------------------------------------------------------------------- /answerkey/parallelism/03.hint.txt: -------------------------------------------------------------------------------- 1 | In order to respect timeouts, we'd need a new `Future` implementation that records the amount of time spent evaluating one future, then subtracts that time from the available time allocated for evaluating the other future. -------------------------------------------------------------------------------- /answerkey/applicative/04.answer.scala: -------------------------------------------------------------------------------- 1 | This transposes the list! That is, we start with a list of rows, each of which is possibly infinite in length. We get back a single row, where each element is the column of values at that position. Try it yourself in the REPL. -------------------------------------------------------------------------------- /answerkey/laziness/08.answer.scala: -------------------------------------------------------------------------------- 1 | // This is more efficient than `cons(a, constant(a))` since it's just 2 | // one object referencing itself. 3 | def constant[A](a: A): Stream[A] = { 4 | lazy val tail: Stream[A] = Cons(() => a, () => tail) 5 | tail 6 | } -------------------------------------------------------------------------------- /answerkey/applicative/10.hint.txt: -------------------------------------------------------------------------------- 1 | You will find this very difficult without an interactive proof assistant like Coq or Agda. If you do decide to take on the challenge, this is the kind of problem that might take someone several days or even a few weeks to think about. -------------------------------------------------------------------------------- /answerkey/datastructures/04.hint.txt: -------------------------------------------------------------------------------- 1 | What should the function do if the `n` argument is 0? 2 | What should it do if the list is empty? 3 | What if the list is not empty and `n` is nonzero? 4 | Consider all of these cases. 5 | Use pattern-matching and recursion. 6 | -------------------------------------------------------------------------------- /answerkey/iomonad/01.answer.scala: -------------------------------------------------------------------------------- 1 | def freeMonad[F[_]]: Monad[({type f[a] = Free[F,a]})#f] = 2 | new Monad[({type f[a] = Free[F,a]})#f] { 3 | def unit[A](a: => A) = Return(a) 4 | def flatMap[A,B](fa: Free[F, A])(f: A => Free[F, B]) = fa flatMap f 5 | } 6 | -------------------------------------------------------------------------------- /answerkey/testing/13.answer.scala: -------------------------------------------------------------------------------- 1 | def listOf1[A](g: Gen[A]): SGen[List[A]] = 2 | SGen(n => g.listOfN(n max 1)) 3 | 4 | val maxProp1 = forAll(listOf1(smallInt)) { l => 5 | val max = l.max 6 | !l.exists(_ > max) // No value greater than `max` should exist in `l` 7 | } -------------------------------------------------------------------------------- /answerkey/monoids/03.hint.txt: -------------------------------------------------------------------------------- 1 | Again we are limited in the number of ways we can combine values with `op` since it should compose functions of type `A => A` for _any_ choice of `A`. And again there is more than one possible implementation. There is only one possible `zero` though. -------------------------------------------------------------------------------- /answerkey/state/02.answer.scala: -------------------------------------------------------------------------------- 1 | // We generate an integer >= 0 and divide it by one higher than the 2 | // maximum. This is just one possible solution. 3 | def double(rng: RNG): (Double, RNG) = { 4 | val (i, r) = nonNegativeInt(rng) 5 | (i / (Int.MaxValue.toDouble + 1), r) 6 | } -------------------------------------------------------------------------------- /answerkey/applicative/18.answer.scala: -------------------------------------------------------------------------------- 1 | def fuse[G[_],H[_],A,B](fa: F[A])(f: A => G[B], g: A => H[B]) 2 | (implicit G: Applicative[G], H: Applicative[H]): (G[F[B]], H[F[B]]) = 3 | traverse[({type f[x] = (G[x], H[x])})#f, A, B](fa)(a => (f(a), g(a)))(G product H) -------------------------------------------------------------------------------- /answerkey/datastructures/13.hint.txt: -------------------------------------------------------------------------------- 1 | It's possible to do both directions. For your `foldLeft` in terms of `foldRight`, 2 | you must build up, using `foldRight`, some value that you can use to achieve the effect 3 | of `foldLeft`. (It won't be the `B` of the return type necessarily) 4 | -------------------------------------------------------------------------------- /answerkey/gettingstarted/02.answer.scala: -------------------------------------------------------------------------------- 1 | def isSorted[A](as: Array[A], gt: (A,A) => Boolean): Boolean = { 2 | @annotation.tailrec 3 | def go(n: Int): Boolean = 4 | if (n >= as.length-1) true 5 | else if (gt(as(n), as(n+1))) false 6 | else go(n+1) 7 | 8 | go(0) 9 | } -------------------------------------------------------------------------------- /answerkey/applicative/01.answer.scala: -------------------------------------------------------------------------------- 1 | def sequence[A](fas: List[F[A]]): F[List[A]] = 2 | traverse(fas)(fa => fa) 3 | 4 | def replicateM[A](n: Int, fa: F[A]): F[List[A]] = 5 | sequence(List.fill(n)(fa)) 6 | 7 | def product[A,B](fa: F[A], fb: F[B]): F[(A,B)] = 8 | map2(fa, fb)((_,_)) -------------------------------------------------------------------------------- /answerkey/monoids/09.hint.txt: -------------------------------------------------------------------------------- 1 | Try creating a data type which tracks the _interval_ of the values in a given segment, as well as whether an 'unordered segment' has been found. 2 | When merging the values for two segments, think about how these two pieces of information should be updated. 3 | -------------------------------------------------------------------------------- /answerkey/datastructures/14.answer.scala: -------------------------------------------------------------------------------- 1 | /* 2 | `append` simply replaces the `Nil` constructor of the first list with the second list, which is exactly the operation performed by `foldRight`. 3 | */ 4 | def appendViaFoldRight[A](l: List[A], r: List[A]): List[A] = 5 | foldRight(l, r)(Cons(_,_)) -------------------------------------------------------------------------------- /answerkey/laziness/03.answer.scala: -------------------------------------------------------------------------------- 1 | /* 2 | It's a common Scala style to write method calls without `.` notation, as in `t() takeWhile f`. 3 | */ 4 | def takeWhile(f: A => Boolean): Stream[A] = this match { 5 | case Cons(h,t) if f(h()) => cons(h(), t() takeWhile f) 6 | case _ => empty 7 | } -------------------------------------------------------------------------------- /answerkey/monoids/07.answer.scala: -------------------------------------------------------------------------------- 1 | def foldMapV[A, B](as: IndexedSeq[A], m: Monoid[B])(f: A => B): B = 2 | if (as.length == 0) 3 | m.zero 4 | else if (as.length == 1) 5 | f(as(0)) 6 | else { 7 | val (l, r) = as.splitAt(as.length / 2) 8 | m.op(foldMapV(l, m)(f), foldMapV(r, m)(f)) 9 | } -------------------------------------------------------------------------------- /answerkey/monoids/08.hint.txt: -------------------------------------------------------------------------------- 1 | Think about what a partial answer looks like. If we've only seen some of the elements of a sequence, we need to know if what we have seen so far is ordered. For every new element we see, if the sequence is in fact ordered, it should not fall inside the range of elements seen already. -------------------------------------------------------------------------------- /answerkey/parallelism/06.answer.scala: -------------------------------------------------------------------------------- 1 | def parFilter[A](l: List[A])(f: A => Boolean): Par[List[A]] = { 2 | val pars: List[Par[List[A]]] = 3 | l map (asyncF((a: A) => if (f(a)) List(a) else List())) 4 | map(sequence(pars))(_.flatten) // convenience method on `List` for concatenating a list of lists 5 | } -------------------------------------------------------------------------------- /exercises/src/main/scala/fpinscala/datastructures/Tree.scala: -------------------------------------------------------------------------------- 1 | package fpinscala.datastructures 2 | 3 | sealed trait Tree[+A] 4 | case class Leaf[A](value: A) extends Tree[A] 5 | case class Branch[A](left: Tree[A], right: Tree[A]) extends Tree[A] 6 | 7 | 8 | object Tree { 9 | 10 | 11 | 12 | 13 | } -------------------------------------------------------------------------------- /answerkey/applicative/19.answer.scala: -------------------------------------------------------------------------------- 1 | def compose[G[_]](implicit G: Traverse[G]): Traverse[({type f[x] = F[G[x]]})#f] = 2 | new Traverse[({type f[x] = F[G[x]]})#f] { 3 | override def traverse[M[_]:Applicative,A,B](fa: F[G[A]])(f: A => M[B]) = 4 | self.traverse(fa)((ga: G[A]) => G.traverse(ga)(f)) 5 | } -------------------------------------------------------------------------------- /answerkey/testing/02.answer.scala: -------------------------------------------------------------------------------- 1 | * The max of a single element list is equal to that element. 2 | * The max of a list is greater than or equal to all elements of the list. 3 | * The max of a list is an element of that list. 4 | * The max of the empty list is unspecified and should throw an error or return `None`. -------------------------------------------------------------------------------- /answerkey/testing/15.hint.txt: -------------------------------------------------------------------------------- 1 | You will need to add to the representation of `Gen`. For example, `Gen[Int]` should be capable of generating random integers as well as generating a stream of all the integers from `Int.MinValue` to `Int.MaxValue`. You may want to have the behavior depend on how many test cases were requested. -------------------------------------------------------------------------------- /answerkey/laziness/15.answer.scala: -------------------------------------------------------------------------------- 1 | /* 2 | The last element of `tails` is always the empty `Stream`, so we handle this as a special case, by appending it to the output. 3 | */ 4 | def tails: Stream[Stream[A]] = 5 | unfold(this) { 6 | case Empty => None 7 | case s => Some((s, s drop 1)) 8 | } append Stream(empty) 9 | -------------------------------------------------------------------------------- /answerkey/parsing/11.answer.scala: -------------------------------------------------------------------------------- 1 | /** In the event of an error, returns the error that occurred after consuming the most number of characters. */ 2 | def furthest[A](p: Parser[A]): Parser[A] 3 | 4 | /** In the event of an error, returns the error that occurred most recently. */ 5 | def latest[A](p: Parser[A]): Parser[A] 6 | -------------------------------------------------------------------------------- /answerkey/parallelism/15.answer.scala: -------------------------------------------------------------------------------- 1 | def flatMap[B](f: A => Par[B]): Par[B] = 2 | Par.flatMap(p)(f) 3 | 4 | def map[B](f: A => B): Par[B] = 5 | Par.map(p)(f) 6 | 7 | def map2[B,C](p2: Par[B])(f: (A,B) => C): Par[C] = 8 | Par.map2(p,p2)(f) 9 | 10 | def zip[B](p2: Par[B]): Par[(A,B)] = 11 | p.map2(p2)((_,_)) -------------------------------------------------------------------------------- /answerkey/parallelism/16.answer.scala: -------------------------------------------------------------------------------- 1 | def flatMap[B](f: A => Par[B]): Par[B] = 2 | Par.flatMap(p)(f) 3 | 4 | def map[B](f: A => B): Par[B] = 5 | Par.map(p)(f) 6 | 7 | def map2[B,C](p2: Par[B])(f: (A,B) => C): Par[C] = 8 | Par.map2(p,p2)(f) 9 | 10 | def zip[B](p2: Par[B]): Par[(A,B)] = 11 | p.map2(p2)((_,_)) -------------------------------------------------------------------------------- /answerkey/testing/08.answer.scala: -------------------------------------------------------------------------------- 1 | def weighted[A](g1: (Gen[A],Double), g2: (Gen[A],Double)): Gen[A] = { 2 | /* The probability we should pull from `g1`. */ 3 | val g1Threshold = g1._2.abs / (g1._2.abs + g2._2.abs) 4 | 5 | Gen(State(RNG.double).flatMap(d => 6 | if (d < g1Threshold) g1._1.sample else g2._1.sample)) 7 | } -------------------------------------------------------------------------------- /answerkey/datastructures/07.answer.scala: -------------------------------------------------------------------------------- 1 | /* 2 | No, this is not possible! The reason is because _before_ we ever call our function, `f`, we evaluate its argument, which in the case of `foldRight` means traversing the list all the way to the end. We need _non-strict_ evaluation to support early termination---we discuss this in chapter 5. 3 | */ -------------------------------------------------------------------------------- /answerkey/monads/02.hint.txt: -------------------------------------------------------------------------------- 1 | Since `State` is a binary type constructor, we need to partially apply it with the `S` type argument. Thus, it is not just one monad, but an entire family of monads, one for each type `S`. You need to devise a way of capturing the type `S` in a type-level scope and providing a partially applied `State` type in that scope. -------------------------------------------------------------------------------- /answerkey/parallelism/14.answer.scala: -------------------------------------------------------------------------------- 1 | // see nonblocking implementation in `Nonblocking.scala` 2 | def join[A](a: Par[Par[A]]): Par[A] = 3 | es => run(es)(run(es)(a).get()) 4 | 5 | def joinViaFlatMap[A](a: Par[Par[A]]): Par[A] = 6 | flatMap(a)(x => x) 7 | 8 | def flatMapViaJoin[A,B](p: Par[A])(f: A => Par[B]): Par[B] = 9 | join(map(p)(f)) -------------------------------------------------------------------------------- /answerkey/testing/18.answer.scala: -------------------------------------------------------------------------------- 1 | * `l.takeWhile(f) ++ l.dropWhile(f) == l` 2 | * We want to enforce that `takeWhile` returns the _longest_ prefix whose elements satisfy the predicate. There are various ways to state this, but the general idea is that the remaining list, if non-empty, should start with an element that does _not_ satisfy the predicate. -------------------------------------------------------------------------------- /answerkey/monads/04.answer.scala: -------------------------------------------------------------------------------- 1 | // Recursive version: 2 | def _replicateM[A](n: Int, ma: F[A]): F[List[A]] = 3 | if (n <= 0) unit(List[A]()) else map2(ma, replicateM(n - 1, ma))(_ :: _) 4 | 5 | // Using `sequence` and the `List.fill` function of the standard library: 6 | def replicateM[A](n: Int, ma: F[A]): F[List[A]] = 7 | sequence(List.fill(n)(ma)) -------------------------------------------------------------------------------- /answerkey/state/07.hint.txt: -------------------------------------------------------------------------------- 1 | You need to recursively iterate over the list. Remember that you can use `foldLeft` or `foldRight` instead of writing a recursive definition. You can also reuse the `map2` function you just wrote. As a test case for your implementation, we should expect `sequence(List(unit(1), unit(2), unit(3)))(r)._1` to return `List(1, 2, 3)`. -------------------------------------------------------------------------------- /answerkey/applicative/05.answer.scala: -------------------------------------------------------------------------------- 1 | def eitherMonad[E]: Monad[({type f[x] = Either[E, x]})#f] = 2 | new Monad[({type f[x] = Either[E, x]})#f] { 3 | def unit[A](a: => A): Either[E, A] = Right(a) 4 | def flatMap[A,B](eea: Either[E, A])(f: A => Either[E, B]) = eea match { 5 | case Right(a) => f(a) 6 | case Left(e) => Left(e) 7 | } 8 | } -------------------------------------------------------------------------------- /answerkey/monads/17.answer.scala: -------------------------------------------------------------------------------- 1 | case class Id[A](value: A) { 2 | def map[B](f: A => B): Id[B] = Id(f(value)) 3 | def flatMap[B](f: A => Id[B]): Id[B] = f(value) 4 | } 5 | 6 | object Id { 7 | val idMonad = new Monad[Id] { 8 | def unit[A](a: => A) = Id(a) 9 | def flatMap[A,B](ida: Id[A])(f: A => Id[B]): Id[B] = ida flatMap f 10 | } 11 | } -------------------------------------------------------------------------------- /answerkey/parallelism/11.answer.scala: -------------------------------------------------------------------------------- 1 | def choiceN[A](n: Par[Int])(choices: List[Par[A]]): Par[A] = 2 | es => { 3 | val ind = run(es)(n).get // Full source files 4 | run(es)(choices(ind)) 5 | } 6 | 7 | def choiceViaChoiceN[A](a: Par[Boolean])(ifTrue: Par[A], ifFalse: Par[A]): Par[A] = 8 | choiceN(map(a)(b => if (b) 0 else 1))(List(ifTrue, ifFalse)) -------------------------------------------------------------------------------- /answers/src/main/scala/fpinscala/streamingio/Partial.scala: -------------------------------------------------------------------------------- 1 | package fpinscala.streamingio 2 | 3 | import language.higherKinds 4 | 5 | /* 6 | * A context in which exceptions can be caught and 7 | * thrown. 8 | */ 9 | trait Partial[F[_]] { 10 | def attempt[A](a: F[A]): F[Either[Throwable,A]] 11 | def fail[A](t: Throwable): F[A] 12 | } 13 | 14 | -------------------------------------------------------------------------------- /answerkey/monoids/06.hint.txt: -------------------------------------------------------------------------------- 1 | Notice that the type of the function that is passed to `foldRight` is `(A, B) => B`, which can be curried to `A => (B => B)`. This is a strong hint that we should use the endofunction monoid `B => B` to implement `foldRight`. The implementation of `foldLeft` is then just the dual. Don't worry if these implementations are not very efficient. -------------------------------------------------------------------------------- /answerkey/errorhandling/07.hint.txt: -------------------------------------------------------------------------------- 1 | The signature of `traverse` is `def traverse[E,A,B](es: List[A])(f: A => Either[E, B]): Either[E, List[B]]`, and the signature of `sequence` is `def sequence[E,A](es: List[Either[E, A]]): Either[E, List[A]]`. In your implementation, you can pattern-match the list and use explicit recursion or use `foldRight` to perform the recursion for you. -------------------------------------------------------------------------------- /answerkey/gettingstarted/03.answer.scala: -------------------------------------------------------------------------------- 1 | /* Note that `=>` associates to the right, so we could write the return type as 2 | `A => B => C` */ 3 | def curry[A,B,C](f: (A, B) => C): A => (B => C) = 4 | a => b => f(a, b) 5 | 6 | /* NB: The `Function2` trait has a `curried` method already, so if you wanted to 7 | cheat a little you could write the answer as f.curried */ -------------------------------------------------------------------------------- /answerkey/applicative/09.answer.scala: -------------------------------------------------------------------------------- 1 | def compose[G[_]](G: Applicative[G]): Applicative[({type f[x] = F[G[x]]})#f] = { 2 | val self = this 3 | new Applicative[({type f[x] = F[G[x]]})#f] { 4 | def unit[A](a: => A) = self.unit(G.unit(a)) 5 | override def map2[A,B,C](fga: F[G[A]], fgb: F[G[B]])(f: (A,B) => C) = 6 | self.map2(fga, fgb)(G.map2(_,_)(f)) 7 | } 8 | } -------------------------------------------------------------------------------- /answerkey/datastructures/03.answer.scala: -------------------------------------------------------------------------------- 1 | /* 2 | If a function body consists solely of a match expression, we'll often put the match on the same line as the function signature, rather than introducing another level of nesting. 3 | */ 4 | def setHead[A](l: List[A], h: A): List[A] = l match { 5 | case Nil => sys.error("setHead on empty list") 6 | case Cons(_,t) => Cons(h,t) 7 | } -------------------------------------------------------------------------------- /answerkey/parsing/06.answer.scala: -------------------------------------------------------------------------------- 1 | /* We'll just have this parser return the number of `"a"` characters read. Note that we can declare a normal value inside a for-comprehension. */ 2 | for { 3 | digit <- "[0-9]+".r 4 | val n = digit.toInt // we really should catch exceptions thrown by toInt and convert to parse failure 5 | _ <- listOfN(n, char('a')) 6 | } yield n 7 | 8 | -------------------------------------------------------------------------------- /answerkey/testing/11.answer.scala: -------------------------------------------------------------------------------- 1 | case class SGen[+A](g: Int => Gen[A]) { 2 | def apply(n: Int): Gen[A] = g(n) 3 | 4 | def map[B](f: A => B): SGen[B] = 5 | SGen(g andThen (_ map f)) 6 | 7 | def flatMap[B](f: A => Gen[B]): SGen[B] = 8 | SGen(g andThen (_ flatMap f)) 9 | 10 | def **[B](s2: SGen[B]): SGen[(A,B)] = 11 | SGen(n => apply(n) ** s2(n)) 12 | } -------------------------------------------------------------------------------- /answerkey/monoids/11.answer.scala: -------------------------------------------------------------------------------- 1 | def count(s: String): Int = { 2 | def wc(c: Char): WC = 3 | if (c.isWhitespace) 4 | Part("", 0, "") 5 | else 6 | Stub(c.toString) 7 | def unstub(s: String) = s.length min 1 8 | foldMapV(s.toIndexedSeq, wcMonoid)(wc) match { 9 | case Stub(s) => unstub(s) 10 | case Part(l, w, r) => unstub(l) + w + unstub(r) 11 | } 12 | } -------------------------------------------------------------------------------- /answerkey/parsing/09.hint.txt: -------------------------------------------------------------------------------- 1 | For the tokens of your grammar, it's often a good idea to skip any trailing whitespace, to avoid having to deal with whitespace everywhere in your grammar. Try introducing a combinator for this. 2 | 3 | When sequencing parsers with `**`, it's common to want to ignore one of the parsers in the sequence, and you'll probably want to introduce combinators for this. -------------------------------------------------------------------------------- /answerkey/applicative/20.answer.scala: -------------------------------------------------------------------------------- 1 | def composeM[G[_],H[_]](implicit G: Monad[G], H: Monad[H], T: Traverse[H]): 2 | Monad[({type f[x] = G[H[x]]})#f] = new Monad[({type f[x] = G[H[x]]})#f] { 3 | def unit[A](a: => A): G[H[A]] = G.unit(H.unit(a)) 4 | override def flatMap[A,B](mna: G[H[A]])(f: A => G[H[B]]): G[H[B]] = 5 | G.flatMap(mna)(na => G.map(T.traverse(na)(f))(H.join)) 6 | } -------------------------------------------------------------------------------- /answerkey/datastructures/26.answer.scala: -------------------------------------------------------------------------------- 1 | /* 2 | We're using the method `max` that exists on all `Int` values rather than an explicit `if` expression. 3 | 4 | Note how similar the implementation is to `size`. We'll abstract out the common pattern in a later exercise. 5 | */ 6 | def maximum(t: Tree[Int]): Int = t match { 7 | case Leaf(n) => n 8 | case Branch(l,r) => maximum(l) max maximum(r) 9 | } -------------------------------------------------------------------------------- /answerkey/monoids/03.answer.scala: -------------------------------------------------------------------------------- 1 | // There is a choice of implementation here as well. 2 | // Do we implement it as `f compose g` or `f andThen g`? We have to pick one. 3 | // We can then get the other one using the `dual` construct (see previous answer). 4 | def endoMonoid[A]: Monoid[A => A] = new Monoid[A => A] { 5 | def op(f: A => A, g: A => A) = f compose g 6 | val zero = (a: A) => a 7 | } -------------------------------------------------------------------------------- /answerkey/applicative/08.answer.scala: -------------------------------------------------------------------------------- 1 | def product[G[_]](G: Applicative[G]): Applicative[({type f[x] = (F[x], G[x])})#f] = { 2 | val self = this 3 | new Applicative[({type f[x] = (F[x], G[x])})#f] { 4 | def unit[A](a: => A) = (self.unit(a), G.unit(a)) 5 | override def apply[A,B](fs: (F[A => B], G[A => B]))(p: (F[A], G[A])) = 6 | (self.apply(fs._1)(p._1), G.apply(fs._2)(p._2)) 7 | } 8 | } -------------------------------------------------------------------------------- /answerkey/state/08.answer.scala: -------------------------------------------------------------------------------- 1 | def flatMap[A,B](f: Rand[A])(g: A => Rand[B]): Rand[B] = 2 | rng => { 3 | val (a, r1) = f(rng) 4 | g(a)(r1) // We pass the new state along 5 | } 6 | 7 | def nonNegativeLessThan(n: Int): Rand[Int] = { 8 | flatMap(nonNegativeInt) { i => 9 | val mod = i % n 10 | if (i + (n-1) - mod >= 0) unit(mod) else nonNegativeLessThan(n) 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /answerkey/iomonad/03.answer.scala: -------------------------------------------------------------------------------- 1 | // Exercise 3: Implement a `Free` interpreter which works for any `Monad` 2 | def run[F[_],A](a: Free[F,A])(implicit F: Monad[F]): F[A] = step(a) match { 3 | case Return(a) => F.unit(a) 4 | case Suspend(r) => r 5 | case FlatMap(Suspend(r), f) => F.flatMap(r)(a => run(f(a))) 6 | case _ => sys.error("Impossible, since `step` eliminates these cases") 7 | } 8 | -------------------------------------------------------------------------------- /answerkey/state/01.answer.scala: -------------------------------------------------------------------------------- 1 | // We need to be quite careful not to skew the generator. 2 | // Since `Int.Minvalue` is 1 smaller than `-(Int.MaxValue)`, 3 | // it suffices to increment the negative numbers by 1 and make them positive. 4 | // This maps Int.MinValue to Int.MaxValue and -1 to 0. 5 | def nonNegativeInt(rng: RNG): (Int, RNG) = { 6 | val (i, r) = rng.nextInt 7 | (if (i < 0) -(i + 1) else i, r) 8 | } -------------------------------------------------------------------------------- /answerkey/gettingstarted/01.answer.scala: -------------------------------------------------------------------------------- 1 | def fib(n: Int): Int = { 2 | @annotation.tailrec 3 | def loop(n: Int, prev: Int, cur: Int): Int = 4 | if (n == 0) prev 5 | else loop(n - 1, cur, prev + cur) 6 | loop(n, 0, 1) 7 | } 8 | 9 | // 0 and 1 are the first two numbers in the sequence, so we start the accumulators with those. 10 | // At every iteration, we add the two numbers to get the next one. -------------------------------------------------------------------------------- /answerkey/streamingio/03.answer.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Exercise 3: Implement `mean`. 3 | * 4 | * This is an explicit recursive definition. We'll factor out a 5 | * generic combinator shortly. 6 | */ 7 | def mean: Process[Double,Double] = { 8 | def go(sum: Double, count: Double): Process[Double,Double] = 9 | await((d: Double) => emit((sum+d) / (count+1), go(sum+d,count+1))) 10 | go(0.0, 0.0) 11 | } 12 | -------------------------------------------------------------------------------- /answerkey/testing/05.answer.scala: -------------------------------------------------------------------------------- 1 | def unit[A](a: => A): Gen[A] = 2 | Gen(State.unit(a)) 3 | 4 | def boolean: Gen[Boolean] = 5 | Gen(State(RNG.boolean)) 6 | 7 | def choose(start: Int, stopExclusive: Int): Gen[Int] = 8 | Gen(State(RNG.nonNegativeInt).map(n => start + n % (stopExclusive-start))) 9 | 10 | def listOfN[A](n: Int, g: Gen[A]): Gen[List[A]] = 11 | Gen(State.sequence(List.fill(n)(g.sample))) -------------------------------------------------------------------------------- /answerkey/iomonad/02.answer.scala: -------------------------------------------------------------------------------- 1 | @annotation.tailrec 2 | def runTrampoline[A](a: Free[Function0,A]): A = (a) match { 3 | case Return(a) => a 4 | case Suspend(r) => r() 5 | case FlatMap(x,f) => x match { 6 | case Return(a) => runTrampoline { f(a) } 7 | case Suspend(r) => runTrampoline { f(r()) } 8 | case FlatMap(a0,g) => runTrampoline { a0 flatMap { a0 => g(a0) flatMap f } } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /answerkey/monoids/04.answer.scala: -------------------------------------------------------------------------------- 1 | import fpinscala.testing._ 2 | import Prop._ 3 | 4 | def monoidLaws[A](m: Monoid[A], gen: Gen[A]): Prop = 5 | // Associativity 6 | forAll(for { 7 | x <- gen 8 | y <- gen 9 | z <- gen 10 | } yield (x, y, z))(p => 11 | m.op(p._1, m.op(p._2, p._3)) == m.op(m.op(p._1, p._2), p._3)) && 12 | // Identity 13 | forAll(gen)((a: A) => 14 | m.op(a, m.zero) == a && m.op(m.zero, a) == a) -------------------------------------------------------------------------------- /answerkey/parallelism/09.answer.scala: -------------------------------------------------------------------------------- 1 | /* 2 | For a thread pool of size 2, `fork(fork(fork(x)))` will deadlock, and so on. Another, perhaps more interesting example is `fork(map2(fork(x), fork(y)))`. In this case, the outer task is submitted first and occupies a thread waiting for both `fork(x)` and `fork(y)`. The `fork(x)` and `fork(y)` tasks are submitted and run in parallel, except that only one thread is available, resulting in deadlock. 3 | */ -------------------------------------------------------------------------------- /answerkey/laziness/07.answer.scala: -------------------------------------------------------------------------------- 1 | def map[B](f: A => B): Stream[B] = 2 | foldRight(empty[B])((h,t) => cons(f(h), t)) 3 | 4 | def filter(f: A => Boolean): Stream[A] = 5 | foldRight(empty[A])((h,t) => 6 | if (f(h)) cons(h, t) 7 | else t) 8 | 9 | def append[B>:A](s: => Stream[B]): Stream[B] = 10 | foldRight(s)((h,t) => cons(h,t)) 11 | 12 | def flatMap[B](f: A => Stream[B]): Stream[B] = 13 | foldRight(empty[B])((h,t) => f(h) append t) 14 | -------------------------------------------------------------------------------- /answerkey/monads/19.answer.scala: -------------------------------------------------------------------------------- 1 | // Getting and setting the same state does nothing: 2 | getState.flatMap(setState) == unit(()) 3 | 4 | // written as for-comprehension: 5 | for { 6 | x <- getState 7 | _ <- setState(x) 8 | } yield () 9 | 10 | // Setting the state to `s` and getting it back out yields `s`. 11 | setState(s).flatMap(_ => getState) == unit(s) 12 | 13 | // alternatively: 14 | for { 15 | _ <- setState(s) 16 | x <- getState 17 | } yield x -------------------------------------------------------------------------------- /answerkey/datastructures/24.hint.txt: -------------------------------------------------------------------------------- 1 | 2 | It's good to specify some properties about these functions up front. For example, do you expect these expressions to be true? 3 | 4 | 5 | ``` 6 | (xs append ys) startsWith xs 7 | xs startsWith Nil 8 | (xs append ys append zs) hasSubsequence ys 9 | xs hasSubsequence Nil 10 | ``` 11 | 12 | You will find that if the answer to any one of these is "yes", then that implies something about the answer to the rest of them. 13 | -------------------------------------------------------------------------------- /answerkey/errorhandling/05.answer.scala: -------------------------------------------------------------------------------- 1 | def traverse[A, B](a: List[A])(f: A => Option[B]): Option[List[B]] = 2 | a match { 3 | case Nil => Some(Nil) 4 | case h::t => map2(f(h), traverse(t)(f))(_ :: _) 5 | } 6 | 7 | def traverse_1[A, B](a: List[A])(f: A => Option[B]): Option[List[B]] = 8 | a.foldRight[Option[List[B]]](Some(Nil))((h,t) => map2(f(h),t)(_ :: _)) 9 | 10 | def sequenceViaTraverse[A](a: List[Option[A]]): Option[List[A]] = 11 | traverse(a)(x => x) 12 | -------------------------------------------------------------------------------- /answerkey/datastructures/10.answer.scala: -------------------------------------------------------------------------------- 1 | /* 2 | It's common practice to annotate functions you expect to be tail-recursive with the `tailrec` annotation. If the function is not tail-recursive, it will yield a compile error, rather than silently compiling the code and resulting in greater stack space usage at runtime. 3 | */ 4 | @annotation.tailrec 5 | def foldLeft[A,B](l: List[A], z: B)(f: (B, A) => B): B = l match { 6 | case Nil => z 7 | case Cons(h,t) => foldLeft(t, f(z,h))(f) 8 | } -------------------------------------------------------------------------------- /answerkey/iomonad/04.answer.scala: -------------------------------------------------------------------------------- 1 | def translate[F[_],G[_],A](f: Free[F,A])(fg: F ~> G): Free[G,A] = { 2 | type FreeG[A] = Free[G,A] 3 | val t = new (F ~> FreeG) { 4 | def apply[A](a: F[A]): Free[G,A] = Suspend { fg(a) } 5 | } 6 | runFree(f)(t)(freeMonad[G]) 7 | } 8 | 9 | def runConsole[A](a: Free[Console,A]): A = 10 | runTrampoline { translate(a)(new (Console ~> Function0) { 11 | def apply[A](c: Console[A]) = c.toThunk 12 | })} 13 | 14 | -------------------------------------------------------------------------------- /answerkey/parsing/07.answer.scala: -------------------------------------------------------------------------------- 1 | /* 2 | These can be implemented using a for-comprehension, which delegates to the `flatMap` and `map` implementations we've provided on `ParserOps`, or they can be implemented in terms of these functions directly. 3 | */ 4 | def product[A,B](p: Parser[A], p2: => Parser[B]): Parser[(A,B)] = 5 | flatMap(p)(a => map(p2)(b => (a,b))) 6 | 7 | def map2[A,B,C](p: Parser[A], p2: => Parser[B])(f: (A,B) => C): Parser[C] = 8 | for { a <- p; b <- p2 } yield f(a,b) -------------------------------------------------------------------------------- /answerkey/streamingio/05.answer.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Exercise 5: Implement `|>`. Let the types guide your implementation. 3 | */ 4 | def |>[O2](p2: Process[O,O2]): Process[I,O2] = { 5 | p2 match { 6 | case Halt() => Halt() 7 | case Emit(h,t) => Emit(h, this |> t) 8 | case Await(f) => this match { 9 | case Emit(h,t) => t |> f(Some(h)) 10 | case Halt() => Halt() |> f(None) 11 | case Await(g) => Await((i: Option[I]) => g(i) |> p2) 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /answerkey/datastructures/23.answer.scala: -------------------------------------------------------------------------------- 1 | /* 2 | This function is usually called `zipWith`. The discussion about stack usage from the explanation of `map` also applies here. By putting the `f` in the second argument list, Scala can infer its type from the previous argument list. 3 | */ 4 | def zipWith[A,B,C](a: List[A], b: List[B])(f: (A,B) => C): List[C] = (a,b) match { 5 | case (Nil, _) => Nil 6 | case (_, Nil) => Nil 7 | case (Cons(h1,t1), Cons(h2,t2)) => Cons(f(h1,h2), zipWith(t1,t2)(f)) 8 | } -------------------------------------------------------------------------------- /answerkey/monads/10.answer.scala: -------------------------------------------------------------------------------- 1 | // We simply substitute the definition of `compose` in terms of `flatMap`. 2 | 3 | compose(f, unit)(v) == f(v) // for all functions f and values v 4 | (a => flatMap(f(a))(unit))(v) == f(v) // Expand `compose` 5 | flatMap(f(v))(unit) == f(v) // Simplify function application 6 | flatMap(x)(unit) == x // Abstract out `f(v)` 7 | 8 | compose(unit, f)(x) == f(x) 9 | flatMap(unit(x))(f) == f(x) // Expand `compose` 10 | 11 | Q.E.D. -------------------------------------------------------------------------------- /answerkey/errorhandling/07.answer.scala: -------------------------------------------------------------------------------- 1 | def traverse[E,A,B](es: List[A])(f: A => Either[E, B]): Either[E, List[B]] = 2 | es match { 3 | case Nil => Right(Nil) 4 | case h::t => (f(h) map2 traverse(t)(f))(_ :: _) 5 | } 6 | 7 | def traverse_1[E,A,B](es: List[A])(f: A => Either[E, B]): Either[E, List[B]] = 8 | es.foldRight[Either[E,List[B]]](Right(Nil))((a, b) => f(a).map2(b)(_ :: _)) 9 | 10 | def sequence[E,A](es: List[Either[E,A]]): Either[E,List[A]] = 11 | traverse(es)(x => x) -------------------------------------------------------------------------------- /answerkey/testing/06.answer.scala: -------------------------------------------------------------------------------- 1 | These methods are defined in the `Gen` class: 2 | 3 | def flatMap[B](f: A => Gen[B]): Gen[B] = 4 | Gen(sample.flatMap(a => f(a).sample)) 5 | 6 | /* A method alias for the function we wrote earlier. */ 7 | def listOfN(size: Int): Gen[List[A]] = 8 | Gen.listOfN(size, this) 9 | 10 | /* A version of `listOfN` that generates the size to use dynamically. */ 11 | def listOfN(size: Gen[Int]): Gen[List[A]] = 12 | size flatMap (n => this.listOfN(n)) -------------------------------------------------------------------------------- /answerkey/testing/16.answer.scala: -------------------------------------------------------------------------------- 1 | /* A `Gen[Par[Int]]` generated from a list summation that spawns a new parallel 2 | * computation for each element of the input list summed to produce the final 3 | * result. This is not the most compelling example, but it provides at least some 4 | * variation in structure to use for testing. 5 | */ 6 | val pint2: Gen[Par[Int]] = choose(-100,100).listOfN(choose(0,20)).map(l => 7 | l.foldLeft(Par.unit(0))((p,i) => 8 | Par.fork { Par.map2(p, Par.unit(i))(_ + _) })) -------------------------------------------------------------------------------- /answerkey/state/10.hint.markdown: -------------------------------------------------------------------------------- 1 | Use the specialized functions for `Rand` as inspiration. 2 | 3 | Recall that if you have a `f : S => (A,S)`, you can create a `State[S,A]` just by writing `State(f)`. The function can also be declared inline with a lambda: 4 | 5 | ```Scala 6 | State { (s: S) => 7 | ... 8 | (a,s2) 9 | } 10 | // or 11 | State ((s: S) => { 12 | ... 13 | (a,s2) 14 | }) 15 | ``` 16 | 17 | We usually use the first form just to avoid an extra level of parentheses and braces. 18 | -------------------------------------------------------------------------------- /answerkey/datastructures/05.answer.scala: -------------------------------------------------------------------------------- 1 | /* 2 | Somewhat overkill, but to illustrate the feature we're using a _pattern guard_, 3 | to only match a `Cons` whose head satisfies our predicate, `f`. 4 | The syntax is to add `if ` after the pattern, before the `=>`, 5 | where `` can use any of the variables introduced by the pattern. 6 | */ 7 | def dropWhile[A](l: List[A], f: A => Boolean): List[A] = 8 | l match { 9 | case Cons(h,t) if f(h) => dropWhile(t, f) 10 | case _ => l 11 | } 12 | -------------------------------------------------------------------------------- /answerkey/parallelism/17.answer.scala: -------------------------------------------------------------------------------- 1 | /* 2 | This implementation is not safe for execution on bounded thread pools, and it also does not preserve timeouts. Can you see why? You may wish to try implementing a nonblocking version like was done for `fork`. 3 | */ 4 | def join[A](a: Par[Par[A]]): Par[A] = 5 | es => a(es).get.apply(es) 6 | 7 | def joinViaFlatMap[A](a: Par[Par[A]]): Par[A] = 8 | flatMap(a)(a => a) 9 | 10 | def flatMapViaJoin[A,B](p: Par[A])(f: A => Par[B]): Par[B] = 11 | join(map(p)(f)) -------------------------------------------------------------------------------- /answerkey/applicative/11.answer.scala: -------------------------------------------------------------------------------- 1 | You want to try writing `flatMap` in terms of `Monad[F]` and `Monad[G]`. 2 | 3 | def flatMap[A,B](mna: F[G[A]])(f: A => F[G[B]]): F[G[B]] = 4 | self.flatMap(na => G.flatMap(na)(a => ???)) 5 | 6 | Here all you have is `f`, which returns an `F[G[B]]`. For it to have the appropriate type to return from the argument to `G.flatMap`, you'd need to be able to "swap" the `F` and `G` types. In other words, you'd need a _distributive law_. Such an operation is not part of the `Monad` interface. -------------------------------------------------------------------------------- /answerkey/monoids/18.answer.scala: -------------------------------------------------------------------------------- 1 | def mapMergeMonoid[K,V](V: Monoid[V]): Monoid[Map[K, V]] = 2 | new Monoid[Map[K, V]] { 3 | def zero = Map[K,V]() 4 | def op(a: Map[K, V], b: Map[K, V]) = 5 | (a.keySet ++ b.keySet).foldLeft(zero) { (acc,k) => 6 | acc.updated(k, V.op(a.getOrElse(k, V.zero), 7 | b.getOrElse(k, V.zero))) 8 | } 9 | } 10 | 11 | def bag[A](as: IndexedSeq[A]): Map[A, Int] = 12 | foldMapV(as, mapMergeMonoid[A, Int](intAddition))((a: A) => Map(a -> 1)) 13 | -------------------------------------------------------------------------------- /answerkey/streamingio/01.answer.scala: -------------------------------------------------------------------------------- 1 | def take[I](n: Int): Process[I,I] = 2 | if (n <= 0) Halt() 3 | else await(i => emit(i, take[I](n-1))) 4 | 5 | def drop[I](n: Int): Process[I,I] = 6 | if (n <= 0) id 7 | else await(i => drop[I](n-1)) 8 | 9 | def takeWhile[I](f: I => Boolean): Process[I,I] = 10 | await(i => 11 | if (f(i)) emit(i, takeWhile(f)) 12 | else Halt()) 13 | 14 | def dropWhile[I](f: I => Boolean): Process[I,I] = 15 | await(i => 16 | if (f(i)) dropWhile(f) 17 | else emit(i,id)) 18 | -------------------------------------------------------------------------------- /answerkey/gettingstarted/04.answer.scala: -------------------------------------------------------------------------------- 1 | def uncurry[A,B,C](f: A => B => C): (A, B) => C = 2 | (a, b) => f(a)(b) 3 | 4 | /* 5 | NB: There is a method on the `Function` object in the standard library, 6 | `Function.uncurried` that you can use for uncurrying. 7 | 8 | Note that we can go back and forth between the two forms. We can curry and uncurry 9 | and the two forms are in some sense "the same". In FP jargon, we say that they 10 | are _isomorphic_ ("iso" = same; "morphe" = shape, form), a term we inherit from 11 | category theory. 12 | */ -------------------------------------------------------------------------------- /answerkey/testing/04.answer.scala: -------------------------------------------------------------------------------- 1 | def choose(start: Int, stopExclusive: Int): Gen[Int] = 2 | Gen(State(RNG.nonNegativeInt).map(n => start + n % (stopExclusive-start))) 3 | 4 | /* We could write this as an explicit state action, but this is far less 5 | convenient, since it requires us to manually thread the `RNG` through the 6 | computation. */ 7 | def choose2(start: Int, stopExclusive: Int): Gen[Int] = 8 | Gen(State(rng => RNG.nonNegativeInt(rng) match { 9 | case (n,rng2) => (start + n % (stopExclusive-start), rng2) 10 | })) -------------------------------------------------------------------------------- /answerkey/monoids/01.answer.scala: -------------------------------------------------------------------------------- 1 | val intAddition: Monoid[Int] = new Monoid[Int] { 2 | def op(x: Int, y: Int) = x + y 3 | val zero = 0 4 | } 5 | 6 | val intMultiplication: Monoid[Int] = new Monoid[Int] { 7 | def op(x: Int, y: Int) = x * y 8 | val zero = 1 9 | } 10 | 11 | val booleanOr: Monoid[Boolean] = new Monoid[Boolean] { 12 | def op(x: Boolean, y: Boolean) = x || y 13 | val zero = false 14 | } 15 | 16 | val booleanAnd: Monoid[Boolean] = new Monoid[Boolean] { 17 | def op(x: Boolean, y: Boolean) = x && y 18 | val zero = true 19 | } -------------------------------------------------------------------------------- /answerkey/monoids/14.answer.scala: -------------------------------------------------------------------------------- 1 | object OptionFoldable extends Foldable[Option] { 2 | override def foldMap[A, B](as: Option[A])(f: A => B)(mb: Monoid[B]): B = 3 | as match { 4 | case None => mb.zero 5 | case Some(a) => f(a) 6 | } 7 | override def foldLeft[A, B](as: Option[A])(z: B)(f: (B, A) => B) = as match { 8 | case None => z 9 | case Some(a) => f(z, a) 10 | } 11 | override def foldRight[A, B](as: Option[A])(z: B)(f: (A, B) => B) = as match { 12 | case None => z 13 | case Some(a) => f(a, z) 14 | } 15 | } -------------------------------------------------------------------------------- /answerkey/gettingstarted/01.hint.txt: -------------------------------------------------------------------------------- 1 | You will definitely need a helper method like we did with `factorial`. But think about what information you need at each iteration. You might need two values, one for each of the two numbers you need to calculate the next number. And you know the first two numbers already. 2 | 3 | Note that the nth Fibonacci number has a closed form solution (see http://en.wikipedia.org/wiki/Fibonacci_number#Closed-form_expression). Using that would be cheating; the point here is just to get some practice writing loops with tail-recursive functions. -------------------------------------------------------------------------------- /answerkey/monoids/08.answer.scala: -------------------------------------------------------------------------------- 1 | // This ability to 'lift' a monoid any monoid to operate within 2 | // some context (here `Par`) is something we'll discuss more in 3 | // chapters 11 & 12 4 | def par[A](m: Monoid[A]): Monoid[Par[A]] = new Monoid[Par[A]] { 5 | def zero = Par.unit(m.zero) 6 | def op(a: Par[A], b: Par[A]) = a.map2(b)(m.op) 7 | } 8 | 9 | // we perform the mapping and the reducing both in parallel 10 | def parFoldMap[A,B](v: IndexedSeq[A], m: Monoid[B])(f: A => B): Par[B] = 11 | Par.parMap(v)(f).flatMap { bs => 12 | foldMapV(bs, par(m))(b => Par.async(b)) 13 | } -------------------------------------------------------------------------------- /answerkey/laziness/14.answer.scala: -------------------------------------------------------------------------------- 1 | /* 2 | `s startsWith s2` when corresponding elements of `s` and `s2` are all equal, until the point that `s2` is exhausted. If `s` is exhausted first, or we find an element that doesn't match, we terminate early. Using non-strictness, we can compose these three separate logical steps--the zipping, the termination when the second stream is exhausted, and the termination if a nonmatching element is found or the first stream is exhausted. 3 | */ 4 | def startsWith[A](s: Stream[A]): Boolean = 5 | zipAll(s).takeWhile(!_._2.isEmpty) forAll { 6 | case (h,h2) => h == h2 7 | } -------------------------------------------------------------------------------- /answerkey/applicative/06.answer.scala: -------------------------------------------------------------------------------- 1 | def validationApplicative[E]: Applicative[({type f[x] = Validation[E,x]})#f] = 2 | new Applicative[({type f[x] = Validation[E,x]})#f] { 3 | def unit[A](a: => A) = Success(a) 4 | override def map2[A,B,C](fa: Validation[E,A], fb: Validation[E,B])(f: (A, B) => C) = 5 | (fa, fb) match { 6 | case (Success(a), Success(b)) => Success(f(a, b)) 7 | case (Failure(h1, t1), Failure(h2, t2)) => 8 | Failure(h1, t1 ++ Vector(h2) ++ t2) 9 | case (e@Failure(_, _), _) => e 10 | case (_, e@Failure(_, _)) => e 11 | } 12 | } -------------------------------------------------------------------------------- /answerkey/testing/14.answer.scala: -------------------------------------------------------------------------------- 1 | val sortedProp = forAll(listOf(smallInt)) { ns => 2 | val nss = ns.sorted 3 | // We specify that every sorted list is either empty, has one element, 4 | // or has no two consecutive elements `(a,b)` such that `a` is greater than `b`. 5 | (nss.isEmpty || nss.tail.isEmpty || !nss.zip(nss.tail).exists { 6 | case (a,b) => a > b 7 | }) 8 | // Also, the sorted list should have all the elements of the input list, 9 | && !ns.exists(!nss.contains(_)) 10 | // and it should have no elements not in the input list. 11 | && !nss.exists(!ns.contains(_)) 12 | } -------------------------------------------------------------------------------- /answerkey/testing/01.answer.scala: -------------------------------------------------------------------------------- 1 | Here are a few properties: 2 | 3 | * The sum of the empty list is 0. 4 | * The sum of a list whose elements are all equal to `x` is just the list's length multiplied by `x`. We might express this as `sum(List.fill(n)(x)) == n*x` 5 | * For any list, `l`, `sum(l) == sum(l.reverse)`, since addition is commutative. 6 | * Given a list, `List(x,y,z,p,q)`, `sum(List(x,y,z,p,q)) == sum(List(x,y)) + sum(List(z,p,q))`, since addition is associative. More generally, we can partition a list into two subsequences whose sum is equal to the sum of the overall list. 7 | * The sum of 1,2,3...n is `n*(n+1)/2`. -------------------------------------------------------------------------------- /answerkey/errorhandling/06.answer.scala: -------------------------------------------------------------------------------- 1 | def map[B](f: A => B): Either[E, B] = 2 | this match { 3 | case Right(a) => Right(f(a)) 4 | case Left(e) => Left(e) 5 | } 6 | 7 | def flatMap[EE >: E, B](f: A => Either[EE, B]): Either[EE, B] = 8 | this match { 9 | case Left(e) => Left(e) 10 | case Right(a) => f(a) 11 | } 12 | def orElse[EE >: E, AA >: A](b: => Either[EE, AA]): Either[EE, AA] = 13 | this match { 14 | case Left(_) => b 15 | case Right(a) => Right(a) 16 | } 17 | def map2[EE >: E, B, C](b: Either[EE, B])(f: (A, B) => C): 18 | Either[EE, C] = for { a <- this; b1 <- b } yield f(a,b1) -------------------------------------------------------------------------------- /answerkey/parallelism/13.answer.scala: -------------------------------------------------------------------------------- 1 | def chooser[A,B](p: Par[A])(choices: A => Par[B]): Par[B] = 2 | es => { 3 | val k = run(es)(p).get 4 | run(es)(choices(k)) 5 | } 6 | 7 | /* `chooser` is usually called `flatMap` or `bind`. */ 8 | def flatMap[A,B](p: Par[A])(choices: A => Par[B]): Par[B] = 9 | es => { 10 | val k = run(es)(p).get 11 | run(es)(choices(k)) 12 | } 13 | 14 | def choiceViaFlatMap[A](p: Par[Boolean])(f: Par[A], t: Par[A]): Par[A] = 15 | flatMap(p)(b => if (b) t else f) 16 | 17 | def choiceNViaFlatMap[A](p: Par[Int])(choices: List[Par[A]]): Par[A] = 18 | flatMap(p)(i => choices(i)) -------------------------------------------------------------------------------- /answerkey/state/04.answer.scala: -------------------------------------------------------------------------------- 1 | // A simple recursive solution 2 | def ints(count: Int)(rng: RNG): (List[Int], RNG) = 3 | if (count <= 0) 4 | (List(), rng) 5 | else { 6 | val (x, r1) = rng.nextInt 7 | val (xs, r2) = ints(count - 1)(r1) 8 | (x :: xs, r2) 9 | } 10 | 11 | // A tail-recursive solution 12 | def ints2(count: Int)(rng: RNG): (List[Int], RNG) = { 13 | def go(count: Int, r: RNG, xs: List[Int]): (List[Int], RNG) = 14 | if (count <= 0) 15 | (xs, r) 16 | else { 17 | val (x, r2) = r.nextInt 18 | go(count - 1, r2, x :: xs) 19 | } 20 | go(count, rng, List()) 21 | } 22 | -------------------------------------------------------------------------------- /answerkey/monoids/06.answer.scala: -------------------------------------------------------------------------------- 1 | // The function type `(A, B) => B`, when curried, is `A => (B => B)`. 2 | // And of course, `B => B` is a monoid for any `B` (via function composition). 3 | def foldRight[A, B](as: List[A])(z: B)(f: (A, B) => B): B = 4 | foldMap(as, endoMonoid[B])(f.curried)(z) 5 | 6 | // Folding to the left is the same except we flip the arguments to 7 | // the function `f` to put the `B` on the correct side. 8 | // Then we have to also "flip" the monoid so that it operates from left to right. 9 | def foldLeft[A, B](as: List[A])(z: B)(f: (B, A) => B): B = 10 | foldMap(as, dual(endoMonoid[B]))(a => b => f(b, a))(z) -------------------------------------------------------------------------------- /answerkey/monads/05.answer.scala: -------------------------------------------------------------------------------- 1 | For `List`, the `replicateM` function will generate a list of lists. It will contain all the lists of length `n` with elements selected from the input list. 2 | 3 | For `Option`, it will generate either `Some` or `None` based on whether the input is `Some` or `None`. The `Some` case will contain a list of length `n` that repeats the element in the input `Option`. 4 | 5 | The general meaning of `replicateM` is described well by the implementation `sequence(List.fill(n)(ma))`. It repeats the `ma` monadic value `n` times and gathers the results in a single value, where the monad `F` determines how values are actually combined. -------------------------------------------------------------------------------- /answerkey/monads/06.answer.scala: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | For `Par`, `filterM` filters a list, applying the functions in 4 | parallel; for `Option`, it filters a list, but allows 5 | the filtering function to fail and abort the filter 6 | computation; for `Gen`, it produces a generator for 7 | subsets of the input list, where the function `f` picks a 8 | 'weight' for each element (in the form of a 9 | `Gen[Boolean]`) 10 | */ 11 | def filterM[A](ms: List[A])(f: A => F[Boolean]): F[List[A]] = 12 | ms match { 13 | case Nil => unit(Nil) 14 | case h :: t => flatMap(f(h))(b => 15 | if (!b) filterM(t)(f) 16 | else map(filterM(t)(f))(h :: _)) 17 | } 18 | -------------------------------------------------------------------------------- /answerkey/state/03.answer.scala: -------------------------------------------------------------------------------- 1 | def intDouble(rng: RNG): ((Int, Double), RNG) = { 2 | val (i, r1) = rng.nextInt 3 | val (d, r2) = double(r1) 4 | ((i, d), r2) 5 | } 6 | 7 | def doubleInt(rng: RNG): ((Double, Int), RNG) = { 8 | val ((i, d), r) = intDouble(rng) 9 | ((d, i), r) 10 | } 11 | 12 | def double3(rng: RNG): ((Double, Double, Double), RNG) = { 13 | val (d1, r1) = double(rng) 14 | val (d2, r2) = double(r1) 15 | val (d3, r3) = double(r2) 16 | ((d1, d2, d3), r3) 17 | } 18 | 19 | // There is something terribly repetitive about passing the RNG along 20 | // every time. What could we do to eliminate some of this duplication 21 | // of effort? -------------------------------------------------------------------------------- /answerkey/monoids/10.answer.scala: -------------------------------------------------------------------------------- 1 | sealed trait WC 2 | case class Stub(chars: String) extends WC 3 | case class Part(lStub: String, words: Int, rStub: String) extends WC 4 | 5 | val wcMonoid: Monoid[WC] = new Monoid[WC] { 6 | // The empty result, where we haven't seen any characters yet. 7 | val zero = Stub("") 8 | 9 | def op(a: WC, b: WC) = (a, b) match { 10 | case (Stub(c), Stub(d)) => Stub(c + d) 11 | case (Stub(c), Part(l, w, r)) => Part(c + l, w, r) 12 | case (Part(l, w, r), Stub(c)) => Part(l, w, r + c) 13 | case (Part(l1, w1, r1), Part(l2, w2, r2)) => 14 | Part(l1, w1 + (if ((r1 + l2).isEmpty) 0 else 1) + w2, r2) 15 | } 16 | } -------------------------------------------------------------------------------- /answerkey/laziness/02.answer.scala: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | `take` first checks if n==0. In that case we need not look at the stream at all. 4 | */ 5 | def take(n: Int): Stream[A] = this match { 6 | case Cons(h, t) if n > 1 => cons(h(), t().take(n - 1)) 7 | case Cons(h, _) if n == 1 => cons(h(), empty) 8 | case _ => empty 9 | } 10 | 11 | 12 | /* 13 | Unlike `take`, `drop` is not incremental. That is, it doesn't generate the 14 | answer lazily. It must traverse the first `n` elements of the stream eagerly. 15 | */ 16 | @annotation.tailrec 17 | final def drop(n: Int): Stream[A] = this match { 18 | case Cons(_, t) if n > 0 => t().drop(n - 1) 19 | case _ => this 20 | } 21 | 22 | -------------------------------------------------------------------------------- /answers/src/main/scala/fpinscala/streamingio/Eq.scala: -------------------------------------------------------------------------------- 1 | package fpinscala.streamingio 2 | 3 | /* 4 | * `Eq[A,B]` provides evidence that types `A` and `B` are equal. 5 | * There is just one public constructor, `Eq.refl`, ensuring that 6 | * we cannot construct an `Eq` instance in which the `A` and `B` 7 | * differ. 8 | * 9 | * There is a version of this in the scala standard library, 10 | * called =:=[A,B] (and usually written infix as `A =:= B`) but 11 | * we include a version here just to show that it is not magic. 12 | */ 13 | case class Eq[A,B] private(to: A => B, from: B => A) 14 | 15 | object Eq { def refl[A]: Eq[A,A] = Eq(identity, identity) } 16 | 17 | -------------------------------------------------------------------------------- /answerkey/laziness/12.answer.scala: -------------------------------------------------------------------------------- 1 | /* 2 | Scala provides shorter syntax when the first action of a function literal is to match on an expression. The function passed to `unfold` in `fibsViaUnfold` is equivalent to `p => p match { case (f0,f1) => ... }`, but we avoid having to choose a name for `p`, only to pattern match on it. 3 | */ 4 | val fibsViaUnfold = 5 | unfold((0,1)) { case (f0,f1) => Some((f0,(f1,f0+f1))) } 6 | 7 | def fromViaUnfold(n: Int) = 8 | unfold(n)(n => Some((n,n+1))) 9 | 10 | def constantViaUnfold[A](a: A) = 11 | unfold(a)(_ => Some((a,a))) 12 | 13 | // could also of course be implemented as constant(1) 14 | val onesViaUnfold = unfold(1)(_ => Some((1,1))) -------------------------------------------------------------------------------- /answerkey/applicative/03.answer.scala: -------------------------------------------------------------------------------- 1 | /* 2 | The pattern is simple. We just curry the function 3 | we want to lift, pass the result to `unit`, and then `apply` 4 | as many times as there are arguments. 5 | Each call to `apply` is a partial application of the function 6 | */ 7 | def map3[A,B,C,D](fa: F[A], 8 | fb: F[B], 9 | fc: F[C])(f: (A, B, C) => D): F[D] = 10 | apply(apply(apply(unit(f.curried))(fa))(fb))(fc) 11 | 12 | def map4[A,B,C,D,E](fa: F[A], 13 | fb: F[B], 14 | fc: F[C], 15 | fd: F[D])(f: (A, B, C, D) => E): F[E] 16 | apply(apply(apply(apply(unit(f.curried))(fa))(fb))(fc))(fd) -------------------------------------------------------------------------------- /answerkey/monads/11.answer.scala: -------------------------------------------------------------------------------- 1 | For `Option`, we again consider both cases `None` and `Some` and expand the equation. 2 | The monadic `unit` is the `Some(_)` constructor. 3 | 4 | // Left identity is trivially true for None: 5 | flatMap(None)(Some(_)) == None 6 | 7 | // And here it is for Some: 8 | flatMap(Some(v))(Some(_)) == Some(v) 9 | // Substitute the definition of `flatMap`: 10 | Some(v) == Some(v) 11 | 12 | // Right identity is just as easy for None: 13 | flatMap(Some(None))(f) == f(None) 14 | // Substitute definition of flatMap: 15 | f(None) == f(None) 16 | 17 | // And for Some: 18 | flatMap(Some(Some(v)))(f) == f(Some(v)) 19 | // Substitute definition of flatMap: 20 | f(Some(v)) == f(Some(v)) -------------------------------------------------------------------------------- /answerkey/parsing/05.answer.scala: -------------------------------------------------------------------------------- 1 | // We could introduce a combinator, `wrap`: 2 | 3 | def wrap[A](p: => Parser[A]): Parser[A] 4 | 5 | // Then define `many` as: 6 | 7 | def many[A](p: Parser[A]): Parser[List[A]] = 8 | map2(p, wrap(many(p)))(_ :: _) or succeed(List()) 9 | 10 | // In the parallelism chapter, we were particularly interested in avoiding having `Par` objects that took as much time and space to build as the corresponding serial computation, and the `delay` combinator let us control this more carefully. Here, this isn't as much of a concern, and having to think carefully each time we `map2` to decide whether we need to call `wrap` seems like unnecessary friction for users of the API. 11 | -------------------------------------------------------------------------------- /answerkey/datastructures/08.answer.scala: -------------------------------------------------------------------------------- 1 | /* 2 | We get back the original list! Why is that? As we mentioned earlier, one way of thinking about what `foldRight` "does" is it replaces the `Nil` constructor of the list with the `z` argument, and it replaces the `Cons` constructor with the given function, `f`. If we just supply `Nil` for `z` and `Cons` for `f`, then we get back the input list. 3 | 4 | foldRight(Cons(1, Cons(2, Cons(3, Nil))), Nil:List[Int])(Cons(_,_)) 5 | Cons(1, foldRight(Cons(2, Cons(3, Nil)), Nil:List[Int])(Cons(_,_))) 6 | Cons(1, Cons(2, foldRight(Cons(3, Nil), Nil:List[Int])(Cons(_,_)))) 7 | Cons(1, Cons(2, Cons(3, foldRight(Nil, Nil:List[Int])(Cons(_,_))))) 8 | Cons(1, Cons(2, Cons(3, Nil))) 9 | */ -------------------------------------------------------------------------------- /answerkey/datastructures/02.answer.scala: -------------------------------------------------------------------------------- 1 | /* 2 | Although we could return `Nil` when the input list is empty, we choose to throw an exception instead. This is a somewhat subjective choice. In our experience, taking the tail of an empty list is often a bug, and silently returning a value just means this bug will be discovered later, further from the place where it was introduced. 3 | 4 | It's generally good practice when pattern matching to use `_` for any variables you don't intend to use on the right hand side of a pattern. This makes it clear the value isn't relevant. 5 | */ 6 | def tail[A](l: List[A]): List[A] = 7 | l match { 8 | case Nil => sys.error("tail of empty list") 9 | case Cons(_,t) => t 10 | } -------------------------------------------------------------------------------- /answerkey/monads/18.answer.scala: -------------------------------------------------------------------------------- 1 | `replicateM` for `State` repeats the same state transition a number of times and returns a list of the results. It's not passing the same starting state many times, but chaining the calls together so that the output state of one is the input state of the next. 2 | 3 | `map2` works similarly in that it takes two state transitions and feeds the output state of one to the input of the other. The outputs are not put in a list, but combined with a function `f`. 4 | 5 | `sequence` takes an entire list of state transitions and does the same kind of thing as `replicateM`: it feeds the output state of the first state transition to the input state of the next, and so on. The results are accumulated in a list. -------------------------------------------------------------------------------- /answerkey/errorhandling/04.answer.scala: -------------------------------------------------------------------------------- 1 | /* 2 | Here's an explicit recursive version: 3 | */ 4 | def sequence[A](a: List[Option[A]]): Option[List[A]] = 5 | a match { 6 | case Nil => Some(Nil) 7 | case h :: t => h flatMap (hh => sequence(t) map (hh :: _)) 8 | } 9 | /* 10 | It can also be implemented using `foldRight` and `map2`. The type annotation on `foldRight` is needed here; otherwise Scala wrongly infers the result type of the fold as `Some[Nil.type]` and reports a type error (try it!). This is an unfortunate consequence of Scala using subtyping to encode algebraic data types. 11 | */ 12 | def sequence_1[A](a: List[Option[A]]): Option[List[A]] = 13 | a.foldRight[Option[List[A]]](Some(Nil))((x,y) => map2(x,y)(_ :: _)) -------------------------------------------------------------------------------- /answerkey/datastructures/19.answer.scala: -------------------------------------------------------------------------------- 1 | /* 2 | The discussion about `map` also applies here. 3 | */ 4 | def filter[A](l: List[A])(f: A => Boolean): List[A] = 5 | foldRight(l, Nil:List[A])((h,t) => if (f(h)) Cons(h,t) else t) 6 | 7 | def filter_1[A](l: List[A])(f: A => Boolean): List[A] = 8 | foldRightViaFoldLeft(l, Nil:List[A])((h,t) => if (f(h)) Cons(h,t) else t) 9 | 10 | def filter_2[A](l: List[A])(f: A => Boolean): List[A] = { 11 | val buf = new collection.mutable.ListBuffer[A] 12 | def go(l: List[A]): Unit = l match { 13 | case Nil => () 14 | case Cons(h,t) => if (f(h)) buf += h; go(t) 15 | } 16 | go(l) 17 | List(buf.toList: _*) // converting from the standard Scala list to the list we've defined here 18 | } -------------------------------------------------------------------------------- /answerkey/monads/15.answer.scala: -------------------------------------------------------------------------------- 1 | We can state the associative law in terms of `join`: 2 | 3 | join(join(x)) == join(map(x)(join)) 4 | 5 | For `Par`, the `join` combinator means something like "make the outer thread wait for the inner one to finish." What this law is saying is that if you have threads starting threads three levels deep, then joining the inner threads and then the outer ones is the same as joining the outer threads and then the inner ones. 6 | 7 | For `Parser`, the `join` combinator is running the outer parser to produce a `Parser`, then running the inner `Parser` _on the remaining input_. The associative law is saying, roughly, that only the _order_ of nesting matters, since that's what affects the order in which the parsers are run. -------------------------------------------------------------------------------- /answerkey/streamingio/10.answer.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Exercise 10: This function is defined only if given a `MonadCatch[F]`. 3 | * Unlike the simple `runLog` interpreter defined in the companion object 4 | * below, this is not tail recursive and responsibility for stack safety 5 | * is placed on the `Monad` instance. 6 | */ 7 | def runLog(implicit F: MonadCatch[F]): F[IndexedSeq[O]] = { 8 | def go(cur: Process[F,O], acc: IndexedSeq[O]): F[IndexedSeq[O]] = 9 | cur match { 10 | case Emit(h,t) => go(t, acc :+ h) 11 | case Halt(End) => F.unit(acc) 12 | case Halt(err) => F.fail(err) 13 | case Await(req,recv) => F.flatMap (F.attempt(req)) { e => go(Try(recv(e)), acc) } 14 | } 15 | go(this, IndexedSeq()) 16 | } 17 | -------------------------------------------------------------------------------- /answerkey/testing/09.answer.scala: -------------------------------------------------------------------------------- 1 | def &&(p: Prop) = Prop { 2 | (max,n,rng) => run(max,n,rng) match { 3 | case Passed => p.run(max, n, rng) 4 | case x => x 5 | } 6 | } 7 | 8 | def ||(p: Prop) = Prop { 9 | (max,n,rng) => run(max,n,rng) match { 10 | // In case of failure, run the other prop. 11 | case Falsified(msg, _) => p.tag(msg).run(max,n,rng) 12 | case x => x 13 | } 14 | } 15 | 16 | /* This is rather simplistic - in the event of failure, we simply prepend 17 | * the given message on a newline in front of the existing message. 18 | */ 19 | def tag(msg: String) = Prop { 20 | (max,n,rng) => run(max,n,rng) match { 21 | case Falsified(e, c) => Falsified(msg + "\n" + e, c) 22 | case x => x 23 | } 24 | } -------------------------------------------------------------------------------- /exercises/src/main/scala/fpinscala/streamingio/MonadCatch.scala: -------------------------------------------------------------------------------- 1 | package fpinscala.streamingio 2 | 3 | import fpinscala.iomonad._ 4 | import language.higherKinds 5 | 6 | /* 7 | * A context in which exceptions can be caught and 8 | * thrown. 9 | */ 10 | trait MonadCatch[F[_]] extends Monad[F] { 11 | def attempt[A](a: F[A]): F[Either[Throwable,A]] 12 | def fail[A](t: Throwable): F[A] 13 | } 14 | 15 | object MonadCatch { 16 | implicit def task = new MonadCatch[Task] { 17 | def unit[A](a: => A): Task[A] = Task.unit(a) 18 | def flatMap[A,B](a: Task[A])(f: A => Task[B]): Task[B] = a flatMap f 19 | def attempt[A](a: Task[A]): Task[Either[Throwable,A]] = a.attempt 20 | def fail[A](err: Throwable): Task[A] = Task.fail(err) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /answers/src/main/scala/fpinscala/streamingio/MonadCatch.scala: -------------------------------------------------------------------------------- 1 | package fpinscala.streamingio 2 | 3 | import fpinscala.iomonad._ 4 | 5 | import language.higherKinds 6 | 7 | /* 8 | * A context in which exceptions can be caught and 9 | * thrown. 10 | */ 11 | trait MonadCatch[F[_]] extends Monad[F] { 12 | def attempt[A](a: F[A]): F[Either[Throwable,A]] 13 | def fail[A](t: Throwable): F[A] 14 | } 15 | 16 | object MonadCatch { 17 | implicit def task = new MonadCatch[Task] { 18 | def unit[A](a: => A): Task[A] = Task.unit(a) 19 | def flatMap[A,B](a: Task[A])(f: A => Task[B]): Task[B] = a flatMap f 20 | def attempt[A](a: Task[A]): Task[Either[Throwable,A]] = a.attempt 21 | def fail[A](err: Throwable): Task[A] = Task.fail(err) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /answerkey/datastructures/04.answer.scala: -------------------------------------------------------------------------------- 1 | /* 2 | Again, it's somewhat subjective whether to throw an exception when asked to drop more elements than the list contains. The usual default for `drop` is not to throw an exception, since it's typically used in cases where this is not indicative of a programming error. If you pay attention to how you use `drop`, it's often in cases where the length of the input list is unknown, and the number of elements to be dropped is being computed from something else. If `drop` threw an exception, we'd have to first compute or check the length and only drop up to that many elements. 3 | */ 4 | def drop[A](l: List[A], n: Int): List[A] = 5 | if (n <= 0) l 6 | else l match { 7 | case Nil => Nil 8 | case Cons(_,t) => drop(t, n-1) 9 | } -------------------------------------------------------------------------------- /answerkey/state/06.answer.scala: -------------------------------------------------------------------------------- 1 | // This implementation of map2 passes the initial RNG to the first argument 2 | // and the resulting RNG to the second argument. It's not necessarily wrong 3 | // to do this the other way around, since the results are random anyway. 4 | // We could even pass the initial RNG to both `f` and `g`, but that might 5 | // have unexpected results. E.g. if both arguments are `RNG.int` then we would 6 | // always get two of the same `Int` in the result. When implementing functions 7 | // like this, it's important to consider how we would test them for 8 | // correctness. 9 | def map2[A,B,C](ra: Rand[A], rb: Rand[B])(f: (A, B) => C): Rand[C] = 10 | rng => { 11 | val (a, r1) = ra(rng) 12 | val (b, r2) = rb(r1) 13 | (f(a, b), r2) 14 | } -------------------------------------------------------------------------------- /answerkey/applicative/13.answer.scala: -------------------------------------------------------------------------------- 1 | val listTraverse = new Traverse[List] { 2 | override def traverse[G[_],A,B](as: List[A])(f: A => G[B])(implicit G: Applicative[G]): G[List[B]] = 3 | as.foldRight(G.unit(List[B]()))((a, fbs) => G.map2(f(a), fbs)(_ :: _)) 4 | } 5 | 6 | val optionTraverse = new Traverse[Option] { 7 | override def traverse[G[_],A,B](oa: Option[A])(f: A => G[B])(implicit G: Applicative[G]): G[Option[B]] = 8 | oa match { 9 | case Some(a) => G.map(f(a))(Some(_)) 10 | case None => G.unit(None) 11 | } 12 | } 13 | 14 | val treeTraverse = new Traverse[Tree] { 15 | override def traverse[G[_],A,B](ta: Tree[A])(f: A => G[B])(implicit G: Applicative[G]): G[Tree[B]] = 16 | G.map2(f(ta.head), listTraverse.traverse(ta.tail)(a => traverse(a)(f)))(Tree(_, _)) 17 | } -------------------------------------------------------------------------------- /answerkey/localeffects/02.answer.scala: -------------------------------------------------------------------------------- 1 | // An action that does nothing 2 | def noop[S] = ST[S,Unit](()) 3 | 4 | def partition[S](a: STArray[S,Int], l: Int, r: Int, pivot: Int): ST[S,Int] = for { 5 | vp <- a.read(pivot) 6 | _ <- a.swap(pivot, r) 7 | j <- STRef(l) 8 | _ <- (l until r).foldLeft(noop[S])((s, i) => for { 9 | _ <- s 10 | vi <- a.read(i) 11 | _ <- if (vi < vp) (for { 12 | vj <- j.read 13 | _ <- a.swap(i, vj) 14 | _ <- j.write(vj + 1) 15 | } yield ()) else noop[S] 16 | } yield ()) 17 | x <- j.read 18 | _ <- a.swap(x, r) 19 | } yield x 20 | 21 | def qs[S](a: STArray[S,Int], l: Int, r: Int): ST[S, Unit] = if (l < r) for { 22 | pi <- partition(a, l, r, l + (r - l) / 2) 23 | _ <- qs(a, l, pi - 1) 24 | _ <- qs(a, pi + 1, r) 25 | } yield () else noop[S] -------------------------------------------------------------------------------- /answerkey/datastructures/22.answer.scala: -------------------------------------------------------------------------------- 1 | /* 2 | To match on multiple values, we can put the values into a pair and match on the pair, as shown next, and the same syntax extends to matching on N values (see sidebar "Pairs and tuples in Scala" for more about pair and tuple objects). You can also (somewhat less conveniently, but a bit more efficiently) nest pattern matches: on the right hand side of the `=>`, simply begin another `match` expression. The inner `match` will have access to all the variables introduced in the outer `match`. 3 | 4 | The discussion about stack usage from the explanation of `map` also applies here. 5 | */ 6 | def addPairwise(a: List[Int], b: List[Int]): List[Int] = (a,b) match { 7 | case (Nil, _) => Nil 8 | case (_, Nil) => Nil 9 | case (Cons(h1,t1), Cons(h2,t2)) => Cons(h1+h2, addPairwise(t1,t2)) 10 | } -------------------------------------------------------------------------------- /answerkey/monads/03.answer.scala: -------------------------------------------------------------------------------- 1 | def sequence[A](lma: List[F[A]]): F[List[A]] = 2 | lma.foldRight(unit(List[A]()))((ma, mla) => map2(ma, mla)(_ :: _)) 3 | 4 | def traverse[A,B](la: List[A])(f: A => F[B]): F[List[B]] = 5 | la.foldRight(unit(List[B]()))((a, mlb) => map2(f(a), mlb)(_ :: _)) 6 | 7 | /** 8 | * 'Balanced' sequencing, which should behave like `sequence`, 9 | * but it can use less stack for some data types. We'll see later 10 | * in this chapter how the monad _laws_ let us conclude both 11 | * definitions 'mean' the same thing. 12 | */ 13 | def bsequence[A](ms: Seq[F[A]]): F[IndexedSeq[A]] = { 14 | if (ms.isEmpty) point(Vector()) 15 | else if (ms.size == 1) ms.head.map(Vector(_)) 16 | else { 17 | val (l,r) = ms.toIndexedSeq.splitAt(ms.length / 2) 18 | map2(bsequence(l), bsequence(r))(_ ++ _) 19 | } 20 | } -------------------------------------------------------------------------------- /answerkey/monads/01.answer.scala: -------------------------------------------------------------------------------- 1 | val parMonad = new Monad[Par] { 2 | def unit[A](a: => A) = Par.unit(a) 3 | def flatMap[A,B](ma: Par[A])(f: A => Par[B]) = Par.flatMap(ma)(f) 4 | } 5 | 6 | def parserMonad[P[+_]](p: Parsers[P]) = new Monad[P] { 7 | def unit[A](a: => A) = p.succeed(a) 8 | def flatMap[A,B](ma: P[A])(f: A => P[B]) = p.flatMap(ma)(f) 9 | } 10 | 11 | val optionMonad = new Monad[Option] { 12 | def unit[A](a: => A) = Some(a) 13 | def flatMap[A,B](ma: Option[A])(f: A => Option[B]) = ma flatMap f 14 | } 15 | 16 | val streamMonad = new Monad[Stream] { 17 | def unit[A](a: => A) = Stream(a) 18 | def flatMap[A,B](ma: Stream[A])(f: A => Stream[B]) = ma flatMap f 19 | } 20 | 21 | val listMonad = new Monad[List] { 22 | def unit[A](a: => A) = List(a) 23 | def flatMap[A,B](ma: List[A])(f: A => List[B]) = ma flatMap f 24 | } -------------------------------------------------------------------------------- /answerkey/state/11.answer.scala: -------------------------------------------------------------------------------- 1 | sealed trait Input 2 | case object Coin extends Input 3 | case object Turn extends Input 4 | 5 | case class Machine(locked: Boolean, candies: Int, coins: Int) 6 | 7 | object Candy { 8 | def update = (i: Input) => (s: Machine) => 9 | (i, s) match { 10 | case (_, Machine(_, 0, _)) => s 11 | case (Coin, Machine(false, _, _)) => s 12 | case (Turn, Machine(true, _, _)) => s 13 | case (Coin, Machine(true, candy, coin)) => 14 | Machine(false, candy, coin + 1) 15 | case (Turn, Machine(false, candy, coin)) => 16 | Machine(true, candy - 1, coin) 17 | } 18 | 19 | def simulateMachine(inputs: List[Input]): State[Machine, (Int, Int)] = for { 20 | _ <- sequence(inputs map (modify[Machine] _ compose update)) 21 | s <- get 22 | } yield (s.coins, s.candies) 23 | } 24 | -------------------------------------------------------------------------------- /answerkey/streamingio/09.answer.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Exercise 9: Write a program that reads degrees fahrenheit as `Double` values from a file, 3 | * converts each temperature to celsius, and writes results to another file. 4 | */ 5 | 6 | // This process defines the here is core logic, a transducer that converts input lines 7 | // (assumed to be temperatures in degrees fahrenheit) to output lines (temperatures in 8 | // degress celsius). Left as an exercise to supply another wrapper like `processFile` 9 | // to actually do the IO and drive the process. 10 | def convertFahrenheit: Process[String,String] = 11 | filter((line: String) => !line.startsWith("#")) |> 12 | filter(line => line.trim.nonEmpty) |> 13 | lift(line => toCelsius(line.toDouble).toString) 14 | 15 | def toCelsius(fahrenheit: Double): Double = 16 | (5.0 / 9.0) * (fahrenheit - 32.0) 17 | -------------------------------------------------------------------------------- /answerkey/streamingio/02.answer.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Exercise 2: Implement `count`. 3 | * 4 | * Here's one implementation, with three stages - we map all inputs 5 | * to 1.0, compute a running sum, then finally convert the output 6 | * back to `Int`. The three stages will be interleaved - as soon 7 | * as the first element is examined, it will be converted to 1.0, 8 | * then added to the running total, and then this running total 9 | * will be converted back to `Int`, then the `Process` will examine 10 | * the next element, and so on. 11 | */ 12 | def count[I]: Process[I,Int] = 13 | lift((i: I) => 1.0) |> sum |> lift(_.toInt) 14 | 15 | /* For comparison, here is an explicit recursive implementation. */ 16 | def count2[I]: Process[I,Int] = { 17 | def go(n: Int): Process[I,Int] = 18 | await((i: I) => emit(n+1, go(n+1))) 19 | go(0) 20 | } 21 | 22 | -------------------------------------------------------------------------------- /answerkey/laziness/16.answer.scala: -------------------------------------------------------------------------------- 1 | /* 2 | The function can't be implemented using `unfold`, since `unfold` generates elements of the `Stream` from left to right. It can be implemented using `foldRight` though. 3 | 4 | The implementation is just a `foldRight` that keeps the accumulated value and the stream of intermediate results, which we `cons` onto during each iteration. When writing folds, it's common to have more state in the fold than is needed to compute the result. Here, we simply extract the accumulated list once finished. 5 | */ 6 | def scanRight[B](z: B)(f: (A, => B) => B): Stream[B] = 7 | foldRight((z, Stream(z)))((a, p0) => { 8 | // p0 is passed by-name and used in by-name args in f and cons. So use lazy val to ensure only one evaluation... 9 | lazy val p1 = p0 10 | val b2 = f(a, p1._1) 11 | (b2, cons(b2, p1._2)) 12 | })._2 -------------------------------------------------------------------------------- /exercises/src/main/scala/fpinscala/testing/Gen.scala: -------------------------------------------------------------------------------- 1 | package fpinscala.testing 2 | 3 | import fpinscala.laziness.Stream 4 | import fpinscala.state._ 5 | import fpinscala.parallelism._ 6 | import fpinscala.parallelism.Par.Par 7 | import Gen._ 8 | import Prop._ 9 | import java.util.concurrent.{Executors,ExecutorService} 10 | 11 | /* 12 | The library developed in this chapter goes through several iterations. This file is just the 13 | shell, which you can fill in and modify while working through the chapter. 14 | */ 15 | 16 | trait Prop { 17 | } 18 | 19 | object Prop { 20 | def forAll[A](gen: Gen[A])(f: A => Boolean): Prop = ??? 21 | } 22 | 23 | object Gen { 24 | def unit[A](a: => A): Gen[A] = ??? 25 | } 26 | 27 | trait Gen[A] { 28 | def map[A,B](f: A => B): Gen[B] = ??? 29 | def flatMap[A,B](f: A => Gen[B]): Gen[B] = ??? 30 | } 31 | 32 | trait SGen[+A] { 33 | 34 | } 35 | 36 | -------------------------------------------------------------------------------- /answerkey/localeffects/03.answer.scala: -------------------------------------------------------------------------------- 1 | import scala.collection.mutable.HashMap 2 | 3 | sealed trait STMap[S,K,V] { 4 | protected def table: HashMap[K,V] 5 | 6 | def size: ST[S,Int] = ST(table.size) 7 | 8 | // Get the value under a key 9 | def apply(k: K): ST[S,V] = ST(table(k)) 10 | 11 | // Get the value under a key, or None if the key does not exist 12 | def get(k: K): ST[S, Option[V]] = ST(table.get(k)) 13 | 14 | // Add a value under a key 15 | def +=(kv: (K, V)): ST[S,Unit] = ST(table += kv) 16 | 17 | // Remove a key 18 | def -=(k: K): ST[S,Unit] = ST(table -= k) 19 | } 20 | 21 | object STMap { 22 | def empty[S,K,V]: ST[S, STMap[S,K,V]] = ST(new STMap[S,K,V] { 23 | val table = HashMap.empty[K,V] 24 | }) 25 | 26 | def fromMap[S,K,V](m: Map[K,V]): ST[S, STMap[S,K,V]] = ST(new STMap[S,K,V] { 27 | val table = (HashMap.newBuilder[K,V] ++= m).result 28 | }) 29 | } -------------------------------------------------------------------------------- /answerkey/monads/16.answer.scala: -------------------------------------------------------------------------------- 1 | Recall the identity laws: 2 | 3 | left identity: flatMap(unit(x))(f) == f(x) 4 | right identity: flatMap(x)(unit) == x 5 | 6 | The left identity law for `Gen`: 7 | The law states that if you take the values generated by `unit(x)` (which are always `x`) and apply `f` to those values, that's exactly the same as the generator returned by `f(x)`. 8 | 9 | The right identity law for `Gen`: 10 | The law states that if you apply `unit` to the values inside the generator `x`, that does not in any way differ from `x` itself. 11 | 12 | The left identity law for `List`: 13 | The law says that wrapping a list in a singleton `List` and then flattening the result is the same as doing nothing. 14 | 15 | The right identity law for `List`: 16 | The law says that if you take every value in a list, wrap each one in a singleton `List`, and then flatten the result, you get the list you started with. -------------------------------------------------------------------------------- /answerkey/monads/09.answer.scala: -------------------------------------------------------------------------------- 1 | Let's rewrite the following in terms of `flatMap`: 2 | 3 | compose(compose(f, g), h) == compose(f, compose(g, h)) 4 | 5 | a => flatMap(compose(f, g)(a))(h) == a => flatMap(f(a))(compose(g, h)) 6 | a => flatMap((b => flatMap(f(b))(g))(a))(h) == a => flatMap(f(a))(b => flatMap(g(b))(h)) 7 | 8 | So far we have just expanded the definition of `compose`. Equals substituted for equals. 9 | Let's simplify the left side a little: 10 | 11 | a => flatMap(flatMap(f(a))(g))(h) == a => flatMap(f(a))(b => flatMap(g(b))(h)) 12 | 13 | Let's simplify again by eliminating the `a` argument and substituting a hypothetical value `x` for `f(a)`: 14 | 15 | flatMap(flatMap(x)(g))(h) == flatMap(x)(b => flatMap(g(b))(h)) 16 | 17 | This now looks exactly like the monad law stated in terms of `flatMap`, just with different names: 18 | 19 | flatMap(flatMap(x)(f))(g) == flatMap(x)(a => flatMap(f(a))(g)) 20 | 21 | Q.E.D. -------------------------------------------------------------------------------- /answerkey/applicative/15.answer.scala: -------------------------------------------------------------------------------- 1 | It's because `foldRight`, `foldLeft`, and `foldMap` don't give us any way of constructing a value of the foldable type. In order to `map` over a structure, you need the ability to create a new structure (such as `Nil` and `Cons` in the case of a `List`). `Traverse` is able to extend `Functor` precisely because a traversal preserves the original structure. 2 | An example of a Foldable that is not a functor: 3 | 4 | case class Iteration[A](a: A, f: A => A, n: Int) { 5 | def foldMap[B](g: A => B)(M: Monoid[B]): B = { 6 | def iterate(n: Int, b: B, c: A): B = 7 | if (n <= 0) b else iterate(n-1, g(c), f(a)) 8 | iterate(n, M.zero, a) 9 | } 10 | } 11 | 12 | This class conceptually represents a sequence of `A` values, generated by repeated function application starting from some seed value. But can you see why it's not possible to define `map` for this type? -------------------------------------------------------------------------------- /answerkey/streamingio/08.answer.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Exercise 8: Implement `exists` 3 | * 4 | * We choose to emit all intermediate values, and not halt. 5 | * See `existsResult` below for a trimmed version. 6 | */ 7 | def exists[I](f: I => Boolean): Process[I,Boolean] = 8 | lift(f) |> any 9 | 10 | /* Emits whether a `true` input has ever been received. */ 11 | def any: Process[Boolean,Boolean] = 12 | loop(false)((b:Boolean,s) => (s || b, s || b)) 13 | 14 | /* A trimmed `exists`, containing just the final result. */ 15 | def existsResult[I](f: I => Boolean) = 16 | exists(f) |> takeThrough(!_) |> dropWhile(!_) |> echo.orElse(emit(false)) 17 | 18 | /* 19 | * Like `takeWhile`, but includes the first element that tests 20 | * false. 21 | */ 22 | def takeThrough[I](f: I => Boolean): Process[I,I] = 23 | takeWhile(f) ++ echo 24 | 25 | /* Awaits then emits a single value, then halts. */ 26 | def echo[I]: Process[I,I] = await(i => emit(i)) 27 | -------------------------------------------------------------------------------- /answerkey/monoids/09.answer.scala: -------------------------------------------------------------------------------- 1 | // This implementation detects only ascending order, 2 | // but you can write a monoid that detects both ascending and descending 3 | // order if you like. 4 | def ordered(ints: IndexedSeq[Int]): Boolean = { 5 | // Our monoid tracks the minimum and maximum element seen so far 6 | // as well as whether the elements are so far ordered. 7 | val mon = new Monoid[Option[(Int, Int, Boolean)]] { 8 | def op(o1: Option[(Int, Int, Boolean)], o2: Option[(Int, Int, Boolean)]) = 9 | (o1, o2) match { 10 | // The ranges should not overlap if the sequence is ordered. 11 | case (Some((x1, y1, p)), Some((x2, y2, q))) => 12 | Some((x1 min x2, y1 max y2, p && q && y1 <= x2)) 13 | case (x, None) => x 14 | case (None, x) => x 15 | } 16 | val zero = None 17 | } 18 | // The empty sequence is ordered, and each element by itself is ordered. 19 | foldMapV(ints, mon)(i => Some((i, i, true))).map(_._3).getOrElse(true) 20 | } -------------------------------------------------------------------------------- /exercises/src/main/scala/fpinscala/parsing/Parsers.scala: -------------------------------------------------------------------------------- 1 | package fpinscala.parsing 2 | 3 | import language.higherKinds 4 | 5 | trait Parsers[Parser[+_]] { self => // so inner classes may call methods of trait 6 | 7 | case class ParserOps[A](p: Parser[A]) { 8 | 9 | 10 | } 11 | 12 | object Laws { 13 | } 14 | } 15 | 16 | case class Location(input: String, offset: Int = 0) { 17 | 18 | lazy val line = input.slice(0,offset+1).count(_ == '\n') + 1 19 | lazy val col = input.slice(0,offset+1).reverse.indexOf('\n') 20 | 21 | def toError(msg: String): ParseError = 22 | ParseError(List((this, msg))) 23 | 24 | def advanceBy(n: Int) = copy(offset = offset+n) 25 | 26 | /* Returns the line corresponding to this location */ 27 | def currentLine: String = 28 | if (input.length > 1) input.lines.drop(line-1).next 29 | else "" 30 | } 31 | 32 | case class ParseError(stack: List[(Location,String)] = List(), 33 | otherFailures: List[ParseError] = List()) { 34 | } -------------------------------------------------------------------------------- /answerkey/errorhandling/08.answer.scala: -------------------------------------------------------------------------------- 1 | /* 2 | There are a number of variations on `Option` and `Either`. If we want to accumulate multiple errors, a simple approach is a new data type that lets us keep a list of errors in the data constructor that represents failures: 3 | 4 | trait Partial[+A,+B] 5 | case class Errors[+A](get: Seq[A]) extends Partial[A,Nothing] 6 | case class Success[+B](get: B) extends Partial[Nothing,B] 7 | 8 | There is a type very similar to this called `Validation` in the Scalaz library. You can implement `map`, `map2`, `sequence`, and so on for this type in such a way that errors are accumulated when possible (`flatMap` is unable to accumulate errors--can you see why?). This idea can even be generalized further--we don't need to accumulate failing values into a list; we can accumulate values using any user-supplied binary function. 9 | 10 | It's also possible to use `Either[List[E],_]` directly to accumulate errors, using different implementations of helper functions like `map2` and `sequence`. 11 | */ -------------------------------------------------------------------------------- /answerkey/state/07.answer.scala: -------------------------------------------------------------------------------- 1 | // In `sequence`, the base case of the fold is a `unit` action that returns 2 | // the empty list. At each step in the fold, we accumulate in `acc` 3 | // and `f` is the current element in the list. 4 | // `map2(f, acc)(_ :: _)` results in a value of type `Rand[List[A]]` 5 | // We map over that to prepend (cons) the element onto the accumulated list. 6 | // 7 | // We are using `foldRight`. If we used `foldLeft` then the values in the 8 | // resulting list would appear in reverse order. It would be arguably better 9 | // to use `foldLeft` followed by `reverse`. What do you think? 10 | def sequence[A](fs: List[Rand[A]]): Rand[List[A]] = 11 | fs.foldRight(unit(List[A]()))((f, acc) => map2(f, acc)(_ :: _)) 12 | 13 | // It's interesting that we never actually need to talk about the `RNG` value 14 | // in `sequence`. This is a strong hint that we could make this function 15 | // polymorphic in that type. 16 | 17 | def _ints(count: Int): Rand[List[Int]] = 18 | sequence(List.fill(count)(int)) 19 | -------------------------------------------------------------------------------- /answerkey/monoids/02.answer.scala: -------------------------------------------------------------------------------- 1 | // Notice that we have a choice in how we implement `op`. 2 | // We can compose the options in either order. Both of those implementations 3 | // satisfy the monoid laws, but they are not equivalent. 4 | // This is true in general--that is, every monoid has a _dual_ where the 5 | // `op` combines things in the opposite order. Monoids like `booleanOr` and 6 | // `intAddition` are equivalent to their duals because their `op` is commutative 7 | // as well as associative. 8 | 9 | def optionMonoid[A]: Monoid[Option[A]] = new Monoid[Option[A]] { 10 | def op(x: Option[A], y: Option[A]) = x orElse y 11 | val zero = None 12 | } 13 | 14 | // We can get the dual of any monoid just by flipping the `op`. 15 | def dual[A](m: Monoid[A]): Monoid[A] = new Monoid[A] { 16 | def op(x: A, y: A): A = m.op(y, x) 17 | val zero = m.zero 18 | } 19 | 20 | // Now we can have both monoids on hand: 21 | def firstOptionMonoid[A]: Monoid[Option[A]] = optionMonoid[A] 22 | def lastOptionMonoid[A]: Monoid[Option[A]] = dual(firstOptionMonoid) -------------------------------------------------------------------------------- /answerkey/streamingio/07.answer.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Exercise 7: Can you think of a generic combinator that would 3 | * allow for the definition of `mean` in terms of `sum` and 4 | * `count`? 5 | * 6 | * Yes, it is `zip`, which feeds the same input to two processes. 7 | * The implementation is a bit tricky, as we have to make sure 8 | * that input gets fed to both `p1` and `p2`. 9 | */ 10 | def zip[A,B,C](p1: Process[A,B], p2: Process[A,C]): Process[A,(B,C)] = 11 | (p1, p2) match { 12 | case (Halt(), _) => Halt() 13 | case (_, Halt()) => Halt() 14 | case (Emit(b, t1), Emit(c, t2)) => Emit((b,c), zip(t1, t2)) 15 | case (Await(recv1), _) => 16 | Await((oa: Option[A]) => zip(recv1(oa), feed(oa)(p2))) 17 | case (_, Await(recv2)) => 18 | Await((oa: Option[A]) => zip(feed(oa)(p1), recv2(oa))) 19 | } 20 | 21 | def feed[A,B](oa: Option[A])(p: Process[A,B]): Process[A,B] = 22 | p match { 23 | case Halt() => p 24 | case Emit(h,t) => Emit(h, feed(oa)(t)) 25 | case Await(recv) => recv(oa) 26 | } 27 | 28 | -------------------------------------------------------------------------------- /answerkey/datastructures/18.answer.scala: -------------------------------------------------------------------------------- 1 | /* 2 | A natural solution is using `foldRight`, but our implementation of `foldRight` is not stack-safe. We can use `foldRightViaFoldLeft` to avoid the stack overflow (variation 1), but more commonly, with our current implementation of `List`, `map` will just be implemented using local mutation (variation 2). Again, note that the mutation isn't observable outside the function, since we're only mutating a buffer that we've allocated. 3 | */ 4 | def map[A,B](l: List[A])(f: A => B): List[B] = 5 | foldRight(l, Nil:List[B])((h,t) => Cons(f(h),t)) 6 | 7 | def map_1[A,B](l: List[A])(f: A => B): List[B] = 8 | foldRightViaFoldLeft(l, Nil:List[B])((h,t) => Cons(f(h),t)) 9 | 10 | def map_2[A,B](l: List[A])(f: A => B): List[B] = { 11 | val buf = new collection.mutable.ListBuffer[B] 12 | def go(l: List[A]): Unit = l match { 13 | case Nil => () 14 | case Cons(h,t) => buf += f(h); go(t) 15 | } 16 | go(l) 17 | List(buf.toList: _*) // converting from the standard Scala list to the list we've defined here 18 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012, Manning Publications, Co. 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /answerkey/datastructures/15.answer.scala: -------------------------------------------------------------------------------- 1 | /* 2 | Since `append` takes time proportional to its first argument, and this first argument never grows because of the right-associativity of `foldRight`, this function is linear in the total length of all lists. You may want to try tracing the execution of the implementation on paper to convince yourself that this works. 3 | 4 | Note that we're simply referencing the `append` function, without writing something like `(x,y) => append(x,y)` or `append(_,_)`. In Scala there is a rather arbitrary distinction between functions defined as _methods_, which are introduced with the `def` keyword, and function values, which are the first-class objects we can pass to other functions, put in collections, and so on. This is a case where Scala lets us pretend the distinction doesn't exist. In other cases, you'll be forced to write `append _` (to convert a `def` to a function value) or even `(x: List[A], y: List[A]) => append(x,y)` if the function is polymorphic and the type arguments aren't known. 5 | */ 6 | def concat[A](l: List[List[A]]): List[A] = 7 | foldRight(l, Nil:List[A])(append) -------------------------------------------------------------------------------- /answerkey/parsing/18.answer.scala: -------------------------------------------------------------------------------- 1 | // We'll just give a sketch here. The basic idea is to add an additional field to `ParseError` 2 | 3 | case class ParseError(stack: List[(Location,String)] = List(), 4 | otherFailures: List[ParseError] = List()) { 5 | 6 | def addFailure(e: ParseError): ParseError = 7 | this.copy(otherFailures = e :: this.otherFailures) 8 | ... 9 | } 10 | 11 | // We then need to make sure we populate this in the implementation of `or` 12 | def or[A](p: Parser[A], p2: => Parser[A]): Parser[A] = 13 | s => p(s) match { 14 | case Failure(e,false) => p2(s).mapError(_.addFailure(e)) 15 | case r => r // committed failure or success skips running `p2` 16 | } 17 | 18 | // Of course, we have to decide how to print a `ParseError` for human consumption 19 | // We also can expose combinators for selecting which error(s) get reported in the 20 | // event that a chain of `a | b | c` fails--we might choose to collect up all the 21 | // errors for each of the three parsers, or perhaps only show the parser that got 22 | // the furthest in the input before failing, etc 23 | -------------------------------------------------------------------------------- /answerkey/streamingio/11.answer.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Create a `Process[IO,O]` from the lines of a file, using 3 | * the `resource` combinator above to ensure the file is closed 4 | * when processing the stream of lines is finished. 5 | */ 6 | def lines(filename: String): Process[IO,String] = 7 | resource 8 | { IO(io.Source.fromFile(filename)) } 9 | { src => 10 | lazy val iter = src.getLines // a stateful iterator 11 | def step = if (iter.hasNext) Some(iter.next) else None 12 | lazy val lines: Process[IO,String] = eval(IO(step)).flatMap { 13 | case None => Halt(End) 14 | case Some(line) => Emit(line, lines) 15 | } 16 | lines 17 | } 18 | { src => eval_ { IO(src.close) } } 19 | 20 | /* Exercise 11: Implement `eval`, `eval_`, and use these to implement `lines`. */ 21 | def eval[F[_],A](a: F[A]): Process[F,A] = 22 | await[F,A,A](a) { 23 | case Left(err) => Halt(err) 24 | case Right(a) => Emit(a, Halt(End)) 25 | } 26 | 27 | /* Evaluate the action purely for its effects. */ 28 | def eval_[F[_],A,B](a: F[A]): Process[F,B] = 29 | eval[F,A](a).drain[B] 30 | 31 | -------------------------------------------------------------------------------- /answerkey/applicative/02.answer.scala: -------------------------------------------------------------------------------- 1 | trait Applicative[F[_]] extends Functor[F] { 2 | // `map2` is implemented by first currying `f` so we get a function 3 | // of type `A => B => C`. This is a function that takes `A` and returns 4 | // another function of type `B => C`. So if we map `f.curried` over an 5 | // `F[A]`, we get `F[B => C]`. Passing that to `apply` along with the 6 | // `F[B]` will give us the desired `F[C]`. 7 | def map2[A,B,C](fa: F[A], fb: F[B])(f: (A, B) => C): F[C] = 8 | apply(map(fa)(f.curried), fb) 9 | 10 | // We simply use `map2` to lift a function into `F` so we can apply it 11 | // to both `fab` and `fa`. The function being lifted here is `_(_)`, 12 | // which is the same as the lambda notation `(f, x) => f(x)`. That is, 13 | // It's a function that takes two arguments: 14 | // 1. A function `f` 15 | // 2. An argument `x` to that function 16 | // and it simply applies `f` to `x`. 17 | def apply[A,B](fab: F[A => B])(fa: F[A]): F[B] = 18 | map2(fab, fa)(_(_)) 19 | def unit[A](a: => A): F[A] 20 | 21 | def map[A,B](fa: F[A])(f: A => B): F[B] = 22 | apply(unit(f))(fa) 23 | } 24 | -------------------------------------------------------------------------------- /answerkey/iomonad/05.answer.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Exercise 5: Implement a non-blocking read from an asynchronous file channel. 3 | * We'll just give the basic idea - here, we construct a `Future` 4 | * by reading from an `AsynchronousFileChannel`, a `java.nio` class 5 | * which supports asynchronous reads. 6 | */ 7 | 8 | import java.nio._ 9 | import java.nio.channels._ 10 | 11 | def read(file: AsynchronousFileChannel, 12 | fromPosition: Long, 13 | numBytes: Int): Par[Either[Throwable, Array[Byte]]] = 14 | Par.async { (cb: Either[Throwable, Array[Byte]] => Unit) => 15 | val buf = ByteBuffer.allocate(numBytes) 16 | file.read(buf, fromPosition, (), new CompletionHandler[Integer, Unit] { 17 | def completed(bytesRead: Integer, ignore: Unit) = { 18 | val arr = new Array[Byte](bytesRead) 19 | buf.slice.get(arr, 0, bytesRead) 20 | cb(Right(arr)) 21 | } 22 | def failed(err: Throwable, ignore: Unit) = 23 | cb(Left(err)) 24 | }) 25 | } 26 | 27 | // note: We can wrap `read` in `Free[Par,A]` using the `Suspend` constructor 28 | -------------------------------------------------------------------------------- /answerkey/monoids/13.answer.scala: -------------------------------------------------------------------------------- 1 | sealed trait Tree[+A] 2 | case class Leaf[A](value: A) extends Tree[A] 3 | case class Branch[A](left: Tree[A], right: Tree[A]) extends Tree[A] 4 | 5 | object TreeFoldable extends Foldable[Tree] { 6 | override def foldMap[A, B](as: Tree[A])(f: A => B)(mb: Monoid[B]): B = as match { 7 | case Leaf(a) => f(a) 8 | case Branch(l, r) => mb.op(foldMap(l)(f)(mb), foldMap(r)(f)(mb)) 9 | } 10 | override def foldLeft[A, B](as: Tree[A])(z: B)(f: (B, A) => B) = as match { 11 | case Leaf(a) => f(z, a) 12 | case Branch(l, r) => foldLeft(r)(foldLeft(l)(z)(f))(f) 13 | } 14 | override def foldRight[A, B](as: Tree[A])(z: B)(f: (A, B) => B) = as match { 15 | case Leaf(a) => f(a, z) 16 | case Branch(l, r) => foldRight(l)(foldRight(r)(z)(f))(f) 17 | } 18 | } 19 | 20 | // Notice that in `TreeFoldable.foldMap`, we don't actually use the `zero` 21 | // from the `Monoid`. This is because there is no empty tree. 22 | // This suggests that there might be a class of types that are foldable 23 | // with something "smaller" than a monoid, consisting only of an 24 | // associative `op`. That kind of object (a monoid without a `zero`) is 25 | // called a semigroup. -------------------------------------------------------------------------------- /answerkey/errorhandling/01.answer.scala: -------------------------------------------------------------------------------- 1 | def map[B](f: A => B): Option[B] = this match { 2 | case None => None 3 | case Some(a) => Some(f(a)) 4 | } 5 | 6 | def getOrElse[B>:A](default: => B): B = this match { 7 | case None => default 8 | case Some(a) => a 9 | } 10 | 11 | def flatMap[B](f: A => Option[B]): Option[B] = 12 | map(f) getOrElse None 13 | 14 | /* 15 | Of course, we can also implement `flatMap` with explicit pattern matching. 16 | */ 17 | def flatMap_1[B](f: A => Option[B]): Option[B] = this match { 18 | case None => None 19 | case Some(a) => f(a) 20 | } 21 | 22 | def orElse[B>:A](ob: => Option[B]): Option[B] = 23 | this map (Some(_)) getOrElse ob 24 | 25 | /* 26 | Again, we can implement this with explicit pattern matching. 27 | */ 28 | def orElse_1[B>:A](ob: => Option[B]): Option[B] = this match { 29 | case None => ob 30 | case _ => this 31 | } 32 | 33 | /* 34 | This can also be defined in terms of `flatMap`. 35 | */ 36 | def filter_1(f: A => Boolean): Option[A] = 37 | flatMap(a => if (f(a)) Some(a) else None) 38 | 39 | /* Or via explicit pattern matching. */ 40 | def filter(f: A => Boolean): Option[A] = this match { 41 | case Some(a) if f(a) => this 42 | case _ => None 43 | } 44 | -------------------------------------------------------------------------------- /answerkey/parallelism/05.answer.scala: -------------------------------------------------------------------------------- 1 | def sequence_simple[A](l: List[Par[A]]): Par[List[A]] = 2 | l.foldRight[Par[List[A]]](unit(List()))((h,t) => map2(h,t)(_ :: _)) 3 | 4 | // This implementation forks the recursive step off to a new logical thread, 5 | // making it effectively tail-recursive. However, we are constructing 6 | // a right-nested parallel program, and we can get better performance by 7 | // dividing the list in half, and running both halves in parallel. 8 | // See `sequenceBalanced` below. 9 | def sequenceRight[A](as: List[Par[A]]): Par[List[A]] = 10 | as match { 11 | case Nil => unit(Nil) 12 | case h :: t => map2(h, fork(sequence(t)))(_ :: _) 13 | } 14 | 15 | // We define `sequenceBalanced` using `IndexedSeq`, which provides an 16 | // efficient function for splitting the sequence in half. 17 | def sequenceBalanced[A](as: IndexedSeq[Par[A]]): Par[IndexedSeq[A]] = fork { 18 | if (as.isEmpty) unit(Vector()) 19 | else if (as.length == 1) map(as.head)(a => Vector(a)) 20 | else { 21 | val (l,r) = as.splitAt(as.length/2) 22 | map2(sequenceBalanced(l), sequenceBalanced(r))(_ ++ _) 23 | } 24 | } 25 | 26 | def sequence[A](as: List[Par[A]]): Par[List[A]] = 27 | map(sequenceBalanced(as.toIndexedSeq))(_.toList) -------------------------------------------------------------------------------- /answers/src/main/scala/fpinscala/iomonad/package.scala: -------------------------------------------------------------------------------- 1 | package fpinscala 2 | 3 | import language.higherKinds 4 | 5 | package object iomonad { 6 | import fpinscala.parallelism.Nonblocking._ 7 | 8 | type IO[A] = IO3.IO[A] 9 | def IO[A](a: => A): IO[A] = IO3.IO[A](a) 10 | 11 | implicit val ioMonad = IO3.freeMonad[Par] 12 | 13 | def now[A](a: A): IO[A] = IO3.Return(a) 14 | 15 | def fork[A](a: => IO[A]): IO[A] = par(Par.lazyUnit(())) flatMap (_ => a) 16 | 17 | def forkUnit[A](a: => A): IO[A] = fork(now(a)) 18 | 19 | def delay[A](a: => A): IO[A] = now(()) flatMap (_ => now(a)) 20 | 21 | def par[A](a: Par[A]): IO[A] = IO3.Suspend(a) 22 | 23 | def async[A](cb: ((A => Unit) => Unit)): IO[A] = 24 | fork(par(Par.async(cb))) 25 | 26 | type Free[F[_], A] = IO3.Free[F, A] 27 | 28 | def Return[A](a: A): IO[A] = IO3.Return[Par,A](a) 29 | 30 | // To run an `IO`, we need an executor service. 31 | // The name we have chosen for this method, `unsafePerformIO`, 32 | // reflects that is is unsafe, i.e. that it has side effects, 33 | // and that it _performs_ the actual I/O. 34 | import java.util.concurrent.ExecutorService 35 | def unsafePerformIO[A](io: IO[A])(implicit E: ExecutorService): A = 36 | Par.run(E) { IO3.run(io)(IO3.parMonad) } 37 | } 38 | -------------------------------------------------------------------------------- /exercises/src/main/scala/fpinscala/iomonad/package.scala: -------------------------------------------------------------------------------- 1 | package fpinscala 2 | 3 | import language.higherKinds 4 | 5 | package object iomonad { 6 | import fpinscala.parallelism.Nonblocking._ 7 | 8 | type IO[A] = IO3.IO[A] 9 | def IO[A](a: => A): IO[A] = IO3.IO[A](a) 10 | 11 | implicit val ioMonad = IO3.freeMonad[Par] 12 | 13 | def now[A](a: A): IO[A] = IO3.Return(a) 14 | 15 | def fork[A](a: => IO[A]): IO[A] = par(Par.lazyUnit(())) flatMap (_ => a) 16 | 17 | def forkUnit[A](a: => A): IO[A] = fork(now(a)) 18 | 19 | def delay[A](a: => A): IO[A] = now(()) flatMap (_ => now(a)) 20 | 21 | def par[A](a: Par[A]): IO[A] = IO3.Suspend(a) 22 | 23 | def async[A](cb: ((A => Unit) => Unit)): IO[A] = 24 | fork(par(Par.async(cb))) 25 | 26 | type Free[F[_], A] = IO3.Free[F, A] 27 | 28 | def Return[A](a: A): IO[A] = IO3.Return[Par,A](a) 29 | 30 | // To run an `IO`, we need an executor service. 31 | // The name we have chosen for this method, `unsafePerformIO`, 32 | // reflects that is is unsafe, i.e. that it has side effects, 33 | // and that it _performs_ the actual I/O. 34 | import java.util.concurrent.ExecutorService 35 | def unsafePerformIO[A](io: IO[A])(implicit E: ExecutorService): A = 36 | Par.run(E) { IO3.run(io)(IO3.parMonad) } 37 | } 38 | -------------------------------------------------------------------------------- /answerkey/applicative/14.answer.scala: -------------------------------------------------------------------------------- 1 | The simplest possible `Applicative` we can use is `Id`: 2 | 3 | type Id[A] = A 4 | 5 | We already know this forms a `Monad`, so it's also an applicative functor: 6 | 7 | val idMonad = new Monad[Id] { 8 | def unit[A](a: => A) = a 9 | override def flatMap[A,B](a: A)(f: A => B): B = f(a) 10 | } 11 | 12 | We can now implement `map` by calling `traverse`, picking `Id` as the `Applicative`: 13 | 14 | def map[A,B](fa: F[A])(f: A => B): F[B] = 15 | traverse[Id, A, B](xs)(f)(idMonad) 16 | 17 | This implementation is suggestive of laws for `traverse`, since we expect this implementation to obey the usual functor laws. See the chapter notes for discussion of the laws for `Traverse`. 18 | 19 | Note that we can define `traverse` in terms of `sequence` and `map`, which means that a valid `Traverse` instance may define `sequence` and `map`, or just `traverse`: 20 | 21 | trait Traverse[F[_]] extends Functor[F] { 22 | def traverse[G[_]:Applicative,A,B](fa: F[A])(f: A => G[B]): G[F[B]] = 23 | sequence(map(fa)(f)) 24 | def sequence[G[_]:Applicative,A](fga: F[G[A]]): G[F[A]] = 25 | traverse(fga)(ga => ga) 26 | def map[A,B](fa: F[A])(f: A => B): F[B] = 27 | traverse[Id, A, B](fa)(f)(idMonad) 28 | } -------------------------------------------------------------------------------- /answerkey/monads/02.answer.scala: -------------------------------------------------------------------------------- 1 | // Since `State` is a binary type constructor, we need to partially apply it 2 | // with the `S` type argument. Thus, it is not just one monad, but an entire 3 | // family of monads, one for each type `S`. One solution is to create a class 4 | // `StateMonads` that accepts the `S` type argument and then has a _type member_ 5 | // for the fully applied `State[S, A]` type inside: 6 | class StateMonads[S] { 7 | type StateS[A] = State[S, A] 8 | 9 | // We can then declare the monad for the `StateS` type constructor: 10 | val monad = new Monad[StateS] { 11 | def unit[A](a: => A): State[S, A] = State(s => (a, s)) 12 | override def flatMap[A,B](st: State[S, A])(f: A => State[S, B]): State[S, B] = 13 | st flatMap f 14 | } 15 | } 16 | 17 | // But we don't have to create a full class like `StateMonads`. We can create 18 | // an anonymous class inline, inside parentheses, and project out its type member `f`. 19 | // This is sometimes called a "type lambda", since it's very similar to a type-level 20 | // anonymous function. 21 | def stateMonad[S] = new Monad[({type f[x] = State[S, x]})#f] { 22 | def unit[A](a: => A): State[S, A] = State(s => (a, s)) 23 | override def flatMap[A,B](st: State[S, A])(f: A => State[S, B]): State[S, B] = 24 | st flatMap f 25 | } -------------------------------------------------------------------------------- /answerkey/datastructures/06.answer.scala: -------------------------------------------------------------------------------- 1 | /* 2 | Note that we're copying the entire list up until the last element. Besides being inefficient, the natural recursive solution will use a stack frame for each element of the list, which can lead to stack overflows for large lists (can you see why?). With lists, it's common to use a temporary, mutable buffer internal to the function (with lazy lists or streams, which we discuss in chapter 5, we don't normally do this). So long as the buffer is allocated internal to the function, the mutation is not observable and RT is preserved. 3 | 4 | Another common convention is to accumulate the output list in reverse order, then reverse it at the end, which doesn't require even local mutation. We'll write a reverse function later in this chapter. 5 | */ 6 | def init[A](l: List[A]): List[A] = 7 | l match { 8 | case Nil => sys.error("init of empty list") 9 | case Cons(_,Nil) => Nil 10 | case Cons(h,t) => Cons(h,init(t)) 11 | } 12 | def init2[A](l: List[A]): List[A] = { 13 | import collection.mutable.ListBuffer 14 | val buf = new ListBuffer[A] 15 | @annotation.tailrec 16 | def go(cur: List[A]): List[A] = cur match { 17 | case Nil => sys.error("init of empty list") 18 | case Cons(_,Nil) => List(buf.toList: _*) 19 | case Cons(h,t) => buf += h; go(t) 20 | } 21 | go(l) 22 | } -------------------------------------------------------------------------------- /answerkey/parsing/02.answer.scala: -------------------------------------------------------------------------------- 1 | `product` is associative. These two expressions are "roughly" equal: 2 | 3 | (a ** b) ** c 4 | a ** (b ** c) 5 | 6 | The only difference is how the pairs are nested. The `(a ** b) ** c` parser returns an `((A,B), C)`, whereas the `a ** (b ** c)` returns an `(A, (B,C))`. We can define functions `unbiasL` and `unbiasR` to convert these nested tuples to flat 3-tuples: 7 | 8 | def unbiasL[A,B,C](p: ((A,B), C)): (A,B,C) = (p._1._1, p._1._2, p._2) 9 | def unbiasR[A,B,C](p: (A, (B,C))): (A,B,C) = (p._1, p._2._1, p._2._2) 10 | 11 | With these, we can now state the associativity property: 12 | 13 | (a ** b) ** c map (unbiasL) == a ** (b ** c) map (unbiasR) 14 | 15 | We'll sometimes just use `~=` when there is an obvious bijection between the two sides: 16 | 17 | (a ** b) ** c ~= a ** (b ** c) 18 | 19 | `map` and `product` also have an interesting relationship--we can `map` either before or after taking the product of two parsers, without affecting the behavior: 20 | 21 | a.map(f) ** b.map(g) == (a ** b) map { case (a,b) => (f(a), g(b)) } 22 | 23 | For instance, if `a` and `b` were both `Parser[String]`, and `f` and `g` both computed the length of a string, it doesn't matter if we map over the result of `a` to compute its length, or whether we do that _after_ the product. 24 | 25 | See chapter 12 for more discussion of these laws. 26 | -------------------------------------------------------------------------------- /answerkey/datastructures/24.answer.scala: -------------------------------------------------------------------------------- 1 | /* 2 | There's nothing particularly bad about this implementation, 3 | except that it's somewhat monolithic and easy to get wrong. 4 | Where possible, we prefer to assemble functions like this using 5 | combinations of other functions. It makes the code more obviously 6 | correct and easier to read and understand. Notice that in this 7 | implementation we need special purpose logic to break out of our 8 | loops early. In Chapter 5 we'll discuss ways of composing functions 9 | like this from simpler components, without giving up the efficiency 10 | of having the resulting functions work in one pass over the data. 11 | 12 | It's good to specify some properties about these functions. 13 | For example, do you expect these expressions to be true? 14 | 15 | (xs append ys) startsWith xs 16 | xs startsWith Nil 17 | (xs append ys append zs) hasSubsequence ys 18 | xs hasSubsequence Nil 19 | */ 20 | @annotation.tailrec 21 | def startsWith[A](l: List[A], prefix: List[A]): Boolean = (l,prefix) match { 22 | case (_,Nil) => true 23 | case (Cons(h,t),Cons(h2,t2)) if h == h2 => startsWith(t, t2) 24 | case _ => false 25 | } 26 | @annotation.tailrec 27 | def hasSubsequence[A](sup: List[A], sub: List[A]): Boolean = sup match { 28 | case Nil => sub == Nil 29 | case _ if startsWith(sup, sub) => true 30 | case Cons(_,t) => hasSubsequence(t, sub) 31 | } 32 | -------------------------------------------------------------------------------- /answerkey/laziness/01.answer.scala: -------------------------------------------------------------------------------- 1 | // The natural recursive solution 2 | def toListRecursive: List[A] = this match { 3 | case Cons(h,t) => h() :: t().toListRecursive 4 | case _ => List() 5 | } 6 | 7 | /* 8 | The above solution will stack overflow for large streams, since it's 9 | not tail-recursive. Here is a tail-recursive implementation. At each 10 | step we cons onto the front of the `acc` list, which will result in the 11 | reverse of the stream. Then at the end we reverse the result to get the 12 | correct order again. 13 | [:ben] are the line breaks above okay? I'm unclear on whether these "hints" are supposed to go in the book or not 14 | */ 15 | def toList: List[A] = { 16 | @annotation.tailrec 17 | def go(s: Stream[A], acc: List[A]): List[A] = s match { 18 | case Cons(h,t) => go(t(), h() :: acc) 19 | case _ => acc 20 | } 21 | go(this, List()).reverse 22 | } 23 | 24 | /* 25 | In order to avoid the `reverse` at the end, we could write it using a 26 | mutable list buffer and an explicit loop instead. Note that the mutable 27 | list buffer never escapes our `toList` method, so this function is 28 | still _pure_. 29 | */ 30 | def toListFast: List[A] = { 31 | val buf = new collection.mutable.ListBuffer[A] 32 | @annotation.tailrec 33 | def go(s: Stream[A]): List[A] = s match { 34 | case Cons(h,t) => 35 | buf += h() 36 | go(t()) 37 | case _ => buf.toList 38 | } 39 | go(this) 40 | } -------------------------------------------------------------------------------- /exercises/src/main/scala/fpinscala/errorhandling/Either.scala: -------------------------------------------------------------------------------- 1 | package fpinscala.errorhandling 2 | 3 | 4 | import scala.{Option => _, Either => _, Left => _, Right => _, _} // hide std library `Option` and `Either`, since we are writing our own in this chapter 5 | 6 | sealed trait Either[+E,+A] { 7 | def map[B](f: A => B): Either[E, B] = sys.error("todo") 8 | 9 | def flatMap[EE >: E, B](f: A => Either[EE, B]): Either[EE, B] = sys.error("todo") 10 | 11 | def orElse[EE >: E, B >: A](b: => Either[EE, B]): Either[EE, B] = sys.error("todo") 12 | 13 | def map2[EE >: E, B, C](b: Either[EE, B])(f: (A, B) => C): Either[EE, C] = sys.error("todo") 14 | } 15 | case class Left[+E](get: E) extends Either[E,Nothing] 16 | case class Right[+A](get: A) extends Either[Nothing,A] 17 | 18 | object Either { 19 | def traverse[E,A,B](es: List[A])(f: A => Either[E, B]): Either[E, List[B]] = sys.error("todo") 20 | 21 | def sequence[E,A](es: List[Either[E,A]]): Either[E,List[A]] = sys.error("todo") 22 | 23 | def mean(xs: IndexedSeq[Double]): Either[String, Double] = 24 | if (xs.isEmpty) 25 | Left("mean of empty list!") 26 | else 27 | Right(xs.sum / xs.length) 28 | 29 | def safeDiv(x: Int, y: Int): Either[Exception, Int] = 30 | try Right(x / y) 31 | catch { case e: Exception => Left(e) } 32 | 33 | def Try[A](a: => A): Either[Exception, A] = 34 | try Right(a) 35 | catch { case e: Exception => Left(e) } 36 | 37 | } -------------------------------------------------------------------------------- /answerkey/laziness/13.answer.scala: -------------------------------------------------------------------------------- 1 | def mapViaUnfold[B](f: A => B): Stream[B] = 2 | unfold(this) { 3 | case Cons(h,t) => Some((f(h()), t())) 4 | case _ => None 5 | } 6 | 7 | def takeViaUnfold(n: Int): Stream[A] = 8 | unfold((this,n)) { 9 | case (Cons(h,t), 1) => Some((h(), (empty, 0))) 10 | case (Cons(h,t), n) if n > 1 => Some((h(), (t(), n-1))) 11 | case _ => None 12 | } 13 | 14 | def takeWhileViaUnfold(f: A => Boolean): Stream[A] = 15 | unfold(this) { 16 | case Cons(h,t) if f(h()) => Some((h(), t())) 17 | case _ => None 18 | } 19 | 20 | def zipWith[B,C](s2: Stream[B])(f: (A,B) => C): Stream[C] = 21 | unfold((this, s2)) { 22 | case (Cons(h1,t1), Cons(h2,t2)) => 23 | Some((f(h1(), h2()), (t1(), t2()))) 24 | case _ => None 25 | } 26 | 27 | // special case of `zip` 28 | def zip[B](s2: Stream[B]): Stream[(A,B)] = 29 | zipWith(s2)((_,_)) 30 | 31 | 32 | def zipAll[B](s2: Stream[B]): Stream[(Option[A],Option[B])] = 33 | zipWithAll(s2)((_,_)) 34 | 35 | def zipWithAll[B, C](s2: Stream[B])(f: (Option[A], Option[B]) => C): Stream[C] = 36 | Stream.unfold((this, s2)) { 37 | case (Empty, Empty) => None 38 | case (Cons(h, t), Empty) => Some(f(Some(h()), Option.empty[B]) -> (t(), empty[B])) 39 | case (Empty, Cons(h, t)) => Some(f(Option.empty[A], Some(h())) -> (empty[A] -> t())) 40 | case (Cons(h1, t1), Cons(h2, t2)) => Some(f(Some(h1()), Some(h2())) -> (t1() -> t2())) 41 | } 42 | -------------------------------------------------------------------------------- /project/Build.scala: -------------------------------------------------------------------------------- 1 | import sbt._ 2 | import Keys._ 3 | 4 | object FPInScalaBuild extends Build { 5 | val opts = Project.defaultSettings ++ Seq( 6 | scalaVersion := "2.11.7", 7 | resolvers += "Typesafe Repository" at "http://repo.typesafe.com/typesafe/releases/" 8 | ) 9 | 10 | lazy val root = 11 | Project(id = "fpinscala", 12 | base = file("."), 13 | settings = opts ++ Seq( 14 | onLoadMessage ~= (_ + nio2check()) 15 | )) aggregate (chapterCode, exercises, answers) 16 | lazy val chapterCode = 17 | Project(id = "chapter-code", 18 | base = file("chaptercode"), 19 | settings = opts) 20 | lazy val exercises = 21 | Project(id = "exercises", 22 | base = file("exercises"), 23 | settings = opts) 24 | lazy val answers = 25 | Project(id = "answers", 26 | base = file("answers"), 27 | settings = opts) 28 | 29 | def nio2check(): String = { 30 | val cls = "java.nio.channels.AsynchronousFileChannel" 31 | try {Class.forName(cls); ""} 32 | catch {case _: ClassNotFoundException => 33 | ("\nWARNING: JSR-203 \"NIO.2\" (" + cls + ") not found.\n" + 34 | "You are probably running Java < 1.7; answers will not compile.\n" + 35 | "You seem to be running " + System.getProperty("java.version") + ".\n" + 36 | "Try `project exercises' before compile, or upgrading your JDK.") 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /answerkey/parallelism/03.answer.scala: -------------------------------------------------------------------------------- 1 | /* This version respects timeouts. See `Map2Future` below. */ 2 | def map2[A,B,C](a: Par[A], b: Par[B])(f: (A,B) => C): Par[C] = 3 | es => { 4 | val (af, bf) = (a(es), b(es)) 5 | Map2Future(af, bf, f) 6 | } 7 | 8 | /* 9 | Note: this implementation will not prevent repeated evaluation if multiple threads call `get` in parallel. We could prevent this using synchronization, but it isn't needed for our purposes here (also, repeated evaluation of pure values won't affect results). 10 | */ 11 | case class Map2Future[A,B,C](a: Future[A], b: Future[B], 12 | f: (A,B) => C) extends Future[C] { 13 | @volatile var cache: Option[C] = None 14 | def isDone = cache.isDefined 15 | def isCancelled = a.isCancelled || b.isCancelled 16 | def cancel(evenIfRunning: Boolean) = 17 | a.cancel(evenIfRunning) || b.cancel(evenIfRunning) 18 | def get = compute(Long.MaxValue) 19 | def get(timeout: Long, units: TimeUnit): C = 20 | compute(TimeUnit.NANOSECONDS.convert(timeout, units)) 21 | 22 | private def compute(timeoutInNanos: Long): C = cache match { 23 | case Some(c) => c 24 | case None => 25 | val start = System.nanoTime 26 | val ar = a.get(timeoutInNanos, TimeUnit.NANOSECONDS) 27 | val stop = System.nanoTime;val aTime = stop-start 28 | val br = b.get(timeoutInNanos - aTime, TimeUnit.NANOSECONDS) 29 | val ret = f(ar, br) 30 | cache = Some(ret) 31 | ret 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /answerkey/monads/20.answer.scala: -------------------------------------------------------------------------------- 1 | object Reader { 2 | def readerMonad[R] = new Monad[({type f[x] = Reader[R,x]})#f] { 3 | def unit[A](a: => A): Reader[R,A] = Reader(_ => a) 4 | def flatMap[A,B](st: Reader[R,A])(f: A => Reader[R,B]): Reader[R,B] = 5 | Reader(r => f(st.run(r)).run(r)) 6 | } 7 | 8 | // A primitive operation for it would be simply to ask for the `R` argument: 9 | def ask[R]: Reader[R, R] = Reader(r => r) 10 | } 11 | 12 | // The action of Reader's `flatMap` is to pass the `r` argument along to both the 13 | // outer Reader and also to the result of `f`, the inner Reader. Similar to how 14 | // `State` passes along a state, except that in `Reader` the "state" is read-only. 15 | 16 | // The meaning of `sequence` here is that if you have a list of functions, you can 17 | // turn it into a function that takes one argument and passes it to all the functions 18 | // in the list, returning a list of the results. 19 | 20 | // The meaning of `join` is simply to pass the same value as both arguments to a 21 | // binary function. 22 | 23 | // The meaning of `replicateM` is to apply the same function a number of times to 24 | // the same argument, returning a list of the results. Note that if this function 25 | // is _pure_, (which it should be), this can be exploited by only applying the 26 | // function once and replicating the result instead of calling the function many times. 27 | // This means the Reader monad can override replicateM to provide a very efficient 28 | // implementation. -------------------------------------------------------------------------------- /answers/src/main/scala/fpinscala/streamingio/These.scala: -------------------------------------------------------------------------------- 1 | package fpinscala.streamingio 2 | 3 | import language.postfixOps 4 | 5 | /* Data type representing either A, B, or both A and B. */ 6 | trait These[+A,+B] { 7 | import These._ 8 | 9 | def bimap[A2,B2](f: A => A2, g: B => B2): These[A2,B2] = 10 | this match { 11 | case This(a) => This(f(a)) 12 | case That(b) => That(g(b)) 13 | case Both(a,b) => Both(f(a), g(b)) 14 | } 15 | 16 | def mapL[A2,B2>:B](f: A => A2): These[A2,B2] = 17 | bimap(f, identity) 18 | 19 | def mapR[A2>:A,B2](f: B => B2): These[A2,B2] = 20 | bimap(identity, f) 21 | 22 | def isBoth = this match { 23 | case Both(_,_) => true 24 | case _ => false 25 | } 26 | } 27 | 28 | object These { 29 | case class This[+A](a: A) extends These[A,Nothing] 30 | case class That[+B](b: B) extends These[Nothing,B] 31 | case class Both[+A,+B](a: A, b: B) extends These[A,B] 32 | 33 | def zipAll[A,B,C](a: Seq[A], b: Seq[B]): Stream[These[A,B]] = 34 | if (a isEmpty) b.toStream.map(That(_)) 35 | else if (b isEmpty) a.toStream.map(This(_)) 36 | else Both(a.head, b.head) #:: zipAll(a.tail, b.tail) 37 | 38 | /* 39 | * Zips together the two `Seq`s, returning the remaining elemnts 40 | * of each (possibly empty). 41 | */ 42 | def zipResidual[A,B,C](a: Seq[A], b: Seq[B]): 43 | (Seq[(A,B)], Seq[A], Seq[B]) = { 44 | val z = a zip b 45 | val len = z.length 46 | (z, a drop len, b drop len) 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /answerkey/monoids/12.answer.scala: -------------------------------------------------------------------------------- 1 | trait Foldable[F[_]] { 2 | def foldRight[A, B](as: F[A])(z: B)(f: (A, B) => B): B = 3 | foldMap(as)(f.curried)(endoMonoid[B])(z) 4 | 5 | def foldLeft[A, B](as: F[A])(z: B)(f: (B, A) => B): B = 6 | foldMap(as)(a => (b: B) => f(b, a))(dual(endoMonoid[B]))(z) 7 | 8 | def foldMap[A, B](as: F[A])(f: A => B)(mb: Monoid[B]): B = 9 | foldRight(as)(mb.zero)((a, b) => mb.op(f(a), b)) 10 | 11 | def concatenate[A](as: F[A])(m: Monoid[A]): A = 12 | foldLeft(as)(m.zero)(m.op) 13 | } 14 | 15 | object ListFoldable extends Foldable[List] { 16 | override def foldRight[A, B](as: List[A])(z: B)(f: (A, B) => B) = 17 | as.foldRight(z)(f) 18 | override def foldLeft[A, B](as: List[A])(z: B)(f: (B, A) => B) = 19 | as.foldLeft(z)(f) 20 | override def foldMap[A, B](as: List[A])(f: A => B)(mb: Monoid[B]): B = 21 | foldLeft(as)(mb.zero)((b, a) => mb.op(b, f(a))) 22 | } 23 | 24 | object IndexedSeqFoldable extends Foldable[IndexedSeq] { 25 | import Monoid._ 26 | override def foldRight[A, B](as: IndexedSeq[A])(z: B)(f: (A, B) => B) = 27 | as.foldRight(z)(f) 28 | override def foldLeft[A, B](as: IndexedSeq[A])(z: B)(f: (B, A) => B) = 29 | as.foldLeft(z)(f) 30 | override def foldMap[A, B](as: IndexedSeq[A])(f: A => B)(mb: Monoid[B]): B = 31 | foldMapV(as, mb)(f) 32 | } 33 | 34 | object StreamFoldable extends Foldable[Stream] { 35 | override def foldRight[A, B](as: Stream[A])(z: B)(f: (A, B) => B) = 36 | as.foldRight(z)(f) 37 | override def foldLeft[A, B](as: Stream[A])(z: B)(f: (B, A) => B) = 38 | as.foldLeft(z)(f) 39 | } -------------------------------------------------------------------------------- /answerkey/applicative/07.answer.scala: -------------------------------------------------------------------------------- 1 | We'll just work through left and right identity, but the basic idea for all these proofs is to substitute the definition of all functions, then use the monad laws to make simplifications to the applicative identities. 2 | 3 | Let's start with left and right identity: 4 | 5 | map2(unit(()), fa)((_,a) => a) == fa // Left identity 6 | map2(fa, unit(()))((a,_) => a) == fa // Right identity 7 | 8 | We'll do left identity first. We expand definition of `map2`: 9 | 10 | def map2[A,B,C](fa: F[A], fb: F[B])(f: (A,B) => C): F[C] 11 | flatMap(fa)(a => map(fb)(b => f(a,b))) 12 | 13 | flatMap(unit())(u => map(fa)(a => a)) == fa 14 | 15 | We just substituted `unit(())` and `(_,a) => a` in for `f`. `map(fa)(a => a)` is just `fa` by the functor laws, giving us: 16 | 17 | flatMap(unit())(u => fa) == fa 18 | 19 | Recall that `flatMap` can be rewritten using `compose`, by using `Unit` as the argument to the first function. 20 | 21 | compose(unit, u => fa)(()) == fa 22 | 23 | And by the monad laws: 24 | 25 | compose(unit, f) == f 26 | 27 | Therefore, `compose(unit, u => fa)` simplifies to `u => fa`. And `u` is just `Unit` here, and is ignored, so this is equivalent to `fa`: 28 | 29 | (u => fa)(()) == fa 30 | fa == fa 31 | 32 | Right identity is symmetric; we just end up using the other identity for `compose`, that `compose(f, unit) == f`. 33 | 34 | flatMap(fa)(a => map(unit(()))(u => a)) == fa 35 | flatMap(fa)(a => unit(a)) == fa // via functor laws 36 | compose(u => fa, unit)(()) == fa 37 | (u => fa)(()) == fa 38 | fa == fa 39 | 40 | Associativity and naturality are left as an exercise. -------------------------------------------------------------------------------- /answerkey/parsing/16.answer.scala: -------------------------------------------------------------------------------- 1 | case class ParseError(stack: List[(Location,String)] = List()) { 2 | def push(loc: Location, msg: String): ParseError = 3 | copy(stack = (loc,msg) :: stack) 4 | 5 | def label[A](s: String): ParseError = 6 | ParseError(latestLoc.map((_,s)).toList) 7 | 8 | def latest: Option[(Location,String)] = 9 | stack.lastOption 10 | 11 | def latestLoc: Option[Location] = 12 | latest map (_._1) 13 | 14 | /** 15 | Display collapsed error stack - any adjacent stack elements with the 16 | same location are combined on one line. For the bottommost error, we 17 | display the full line, with a caret pointing to the column of the error. 18 | Example: 19 | 20 | 1.1 file 'companies.json'; array 21 | 5.1 object 22 | 5.2 key-value 23 | 5.10 ':' 24 | 25 | { "MSFT" ; 24, 26 | ^ 27 | */ 28 | override def toString = 29 | if (stack.isEmpty) "no error message" 30 | else { 31 | val collapsed = collapseStack(stack) 32 | val context = 33 | collapsed.lastOption.map("\n\n" + _._1.currentLine).getOrElse("") + 34 | collapsed.lastOption.map("\n" + _._1.columnCaret).getOrElse("") 35 | collapsed.map { case (loc,msg) => loc.line.toString + "." + loc.col + " " + msg }.mkString("\n") + 36 | context 37 | } 38 | 39 | /* Builds a collapsed version of the given error stack - 40 | * messages at the same location have their messages merged, 41 | * separated by semicolons */ 42 | def collapseStack(s: List[(Location,String)]): List[(Location,String)] = 43 | s.groupBy(_._1). 44 | mapValues(_.map(_._2).mkString("; ")). 45 | toList.sortBy(_._1.offset) 46 | 47 | def formatLoc(l: Location): String = l.line + "." + l.col 48 | } 49 | -------------------------------------------------------------------------------- /answers/src/main/scala/fpinscala/iomonad/BindTest.scala: -------------------------------------------------------------------------------- 1 | package fpinscala.iomonad 2 | 3 | import language.higherKinds 4 | import language.postfixOps 5 | 6 | object BindTest extends App { 7 | 8 | def timeit(n: Int)(task: => Unit): Unit = { 9 | val start = System.currentTimeMillis 10 | (0 to n).foreach { _ => task } 11 | val stop = System.currentTimeMillis 12 | println((stop - start) / 1000.0 + " seconds") 13 | } 14 | 15 | val N = 100000 16 | def go[F[_]](F: Monad[F])(unit: F[Unit])(f: F[Int] => Int): Unit = { 17 | import F.toMonadic 18 | f { (0 to N).map(i => F.map(unit)(_ => i)).foldLeft(F.unit(0)) { 19 | (f1,f2) => for { 20 | acc <- f1 21 | i <- f2 22 | } yield { // if (i == N) println("result: " + (acc+i)) 23 | (acc + i) 24 | } 25 | }} 26 | } 27 | 28 | import fpinscala.parallelism.Nonblocking._ 29 | 30 | object ParMonad extends Monad[Par] { 31 | def unit[A](a: => A) = Par.unit(a) 32 | def flatMap[A,B](pa: Par[A])(f: A => Par[B]) = Par.fork { Par.flatMap(pa)(f) } 33 | } 34 | 35 | val pool = java.util.concurrent.Executors.newFixedThreadPool(4) 36 | 37 | timeit(10) { go(Throw)(Throw.unit(())) ( _ run ) } 38 | timeit(10) { go(IO2b.TailRec)(IO2b.TailRec.unit(())) ( IO2b.run ) } 39 | timeit(10) { go(IO2c.Async)(IO2c.Async.unit(()))(r => Par.run(pool) { IO2c.run(r) }) } 40 | timeit(10) { go[IO](ioMonad)(ioMonad.unit(()))(r => unsafePerformIO(r)(pool)) } 41 | timeit(10) { go(Task)(Task.now(()))(r => r.run(pool)) } 42 | timeit(10) { go(Task)(Task.forkUnit(()))(r => r.run(pool)) } 43 | timeit(10) { go(ParMonad)(ParMonad.unit(())) { p => Par.run(pool)(p) }} 44 | 45 | // Par.run(pool)(ParMonad.forever { ParMonad.unit { println("woot") }}) 46 | pool.shutdown() 47 | } 48 | -------------------------------------------------------------------------------- /answerkey/datastructures/29.answer.scala: -------------------------------------------------------------------------------- 1 | /* 2 | Like `foldRight` for lists, `fold` receives a "handler" for each of the data constructors of the type, and recursively accumulates some value using these handlers. As with `foldRight`, `fold(t)(Leaf(_))(Branch(_,_)) == t`, and we can use this function to implement just about any recursive function that would otherwise be defined by pattern matching. 3 | */ 4 | def fold[A,B](t: Tree[A])(f: A => B)(g: (B,B) => B): B = t match { 5 | case Leaf(a) => f(a) 6 | case Branch(l,r) => g(fold(l)(f)(g), fold(r)(f)(g)) 7 | } 8 | 9 | def sizeViaFold[A](t: Tree[A]): Int = 10 | fold(t)(a => 1)(1 + _ + _) 11 | 12 | def maximumViaFold(t: Tree[Int]): Int = 13 | fold(t)(a => a)(_ max _) 14 | 15 | def depthViaFold[A](t: Tree[A]): Int = 16 | fold(t)(a => 0)((d1,d2) => 1 + (d1 max d2)) 17 | 18 | /* 19 | Note the type annotation required on the expression `Leaf(f(a))`. Without this annotation, we get an error like this: 20 | 21 | type mismatch; 22 | found : fpinscala.datastructures.Branch[B] 23 | required: fpinscala.datastructures.Leaf[B] 24 | fold(t)(a => Leaf(f(a)))(Branch(_,_)) 25 | ^ 26 | 27 | This error is an unfortunate consequence of Scala using subtyping to encode algebraic data types. Without the annotation, the result type of the fold gets inferred as `Leaf[B]` and it is then expected that the second argument to `fold` will return `Leaf[B]`, which it doesn't (it returns `Branch[B]`). Really, we'd prefer Scala to infer `Tree[B]` as the result type in both cases. When working with algebraic data types in Scala, it's somewhat common to define helper functions that simply call the corresponding data constructors but give the less specific result type: 28 | 29 | def leaf[A](a: A): Tree[A] = Leaf(a) 30 | def branch[A](l: Tree[A], r: Tree[A]): Tree[A] = Branch(l, r) 31 | */ 32 | def mapViaFold[A,B](t: Tree[A])(f: A => B): Tree[B] = 33 | fold(t)(a => Leaf(f(a)): Tree[B])(Branch(_,_)) -------------------------------------------------------------------------------- /exercises/src/main/scala/fpinscala/errorhandling/Option.scala: -------------------------------------------------------------------------------- 1 | package fpinscala.errorhandling 2 | 3 | 4 | import scala.{Option => _, Some => _, Either => _, _} // hide std library `Option`, `Some` and `Either`, since we are writing our own in this chapter 5 | 6 | sealed trait Option[+A] { 7 | def map[B](f: A => B): Option[B] = sys.error("todo") 8 | 9 | def getOrElse[B>:A](default: => B): B = sys.error("todo") 10 | 11 | def flatMap[B](f: A => Option[B]): Option[B] = sys.error("todo") 12 | 13 | def orElse[B>:A](ob: => Option[B]): Option[B] = sys.error("todo") 14 | 15 | def filter(f: A => Boolean): Option[A] = sys.error("todo") 16 | } 17 | case class Some[+A](get: A) extends Option[A] 18 | case object None extends Option[Nothing] 19 | 20 | object Option { 21 | def failingFn(i: Int): Int = { 22 | val y: Int = throw new Exception("fail!") // `val y: Int = ...` declares `y` as having type `Int`, and sets it equal to the right hand side of the `=`. 23 | try { 24 | val x = 42 + 5 25 | x + y 26 | } 27 | catch { case e: Exception => 43 } // A `catch` block is just a pattern matching block like the ones we've seen. `case e: Exception` is a pattern that matches any `Exception`, and it binds this value to the identifier `e`. The match returns the value 43. 28 | } 29 | 30 | def failingFn2(i: Int): Int = { 31 | try { 32 | val x = 42 + 5 33 | x + ((throw new Exception("fail!")): Int) // A thrown Exception can be given any type; here we're annotating it with the type `Int` 34 | } 35 | catch { case e: Exception => 43 } 36 | } 37 | 38 | def mean(xs: Seq[Double]): Option[Double] = 39 | if (xs.isEmpty) None 40 | else Some(xs.sum / xs.length) 41 | def variance(xs: Seq[Double]): Option[Double] = sys.error("todo") 42 | 43 | def map2[A,B,C](a: Option[A], b: Option[B])(f: (A, B) => C): Option[C] = sys.error("todo") 44 | 45 | def sequence[A](a: List[Option[A]]): Option[List[A]] = sys.error("todo") 46 | 47 | def traverse[A, B](a: List[A])(f: A => Option[B]): Option[List[B]] = sys.error("todo") 48 | } -------------------------------------------------------------------------------- /project/master/errorhandling.chapter: -------------------------------------------------------------------------------- 1 | chapter errorhandling #[ 2 | 3 | header #[ ]# 4 | example option #[ 5 | 6 | trait Option[+A] 7 | case class Some[+A](get: A) extends Option[A] 8 | case object None extends Option[Nothing] 9 | 10 | ]# 11 | 12 | header #[ 13 | trait Option[+A] { 14 | ]# 15 | 16 | question map #[ 17 | prompt #[ 18 | def map[B](f: A => B): Option[B] = ]# 19 | 20 | hint #[ Try pattern matching on `this`. ]# 21 | 22 | hint #[ 23 | this match { 24 | case None => None 25 | case Some(a) => ?? 26 | } 27 | ]# 28 | 29 | answer #[ 30 | this match { 31 | case None => None 32 | case Some(a) => Some(f(a)) 33 | } 34 | ]# 35 | 36 | explanation #[ 37 | When implementing functions on ADTs, it's very common to 38 | pattern match and provide a way to handle each data constructor. 39 | ]# 40 | ]# 41 | 42 | question getOrElse #[ 43 | prompt #[ 44 | def getOrElse[B>:A](default: => B): B = ]# 45 | 46 | answer #[ 47 | this match { 48 | case None => default 49 | case Some(a) => a 50 | } 51 | ]# 52 | ]# 53 | 54 | question flatMap #[ 55 | prompt #[ 56 | def flatMap[B](f: A => Option[B]): Option[B] = ]# 57 | 58 | hint #[ 59 | This can be implemented using pattern matching on `this`. It can also be 60 | written using only `map` and `getOrElse`. 61 | ]# 62 | 63 | answer #[ 64 | this map f getOrElse None 65 | ]# 66 | 67 | explanation #[ 68 | This could be implemented with pattern matching as well: 69 | 70 | ~~~ scala 71 | def flatMap[B](f: A => Option[B]): Option[B] = 72 | this match { 73 | case None => None 74 | case Some(a) => f(a) 75 | } 76 | ~~~ 77 | ]# 78 | ]# 79 | 80 | question isDefined #[ 81 | answer #[ 82 | def isDefined: Boolean = this match { 83 | case None => false 84 | case _ => true 85 | } 86 | ]# 87 | ]# 88 | 89 | footer #[ 90 | } 91 | case object None extends Option[Nothing] 92 | case class Some[+A](get: A) extends Option[A] 93 | ]# 94 | 95 | ]# 96 | -------------------------------------------------------------------------------- /answers/src/main/scala/fpinscala/iomonad/Throw.scala: -------------------------------------------------------------------------------- 1 | package fpinscala.iomonad 2 | 3 | /** 4 | * A version of `TailRec` implemented using exceptions. 5 | * In the implementation of `flatMap`, rather than calling 6 | * the function, we throw an exception indicating what 7 | * function we want to call. A central loop repeatedly tries 8 | * and catches these exceptions to force the computation. 9 | */ 10 | trait Throw[+A] { 11 | import Throw._ 12 | 13 | @annotation.tailrec 14 | final def run: A = this match { 15 | case Done(a) => a 16 | case More(thunk) => force(thunk).run 17 | } 18 | } 19 | 20 | object Throw extends Monad[Throw] { 21 | 22 | /* Exception indicating that the central loop should call `f(a)`. */ 23 | case class Call[A,+B] private[Throw] (a: A, f: A => B) extends Exception { 24 | override def fillInStackTrace = this 25 | } 26 | 27 | case class Done[+A](a: A) extends Throw[A] 28 | case class More[+A](thunk: () => Throw[A]) extends Throw[A] 29 | 30 | /* Defer evaluation of `f(a)` to the central evaluation loop. */ 31 | def defer[A,B](a: A)(f: A => B): B = 32 | throw new Call(a, f) 33 | 34 | /* Central evaluation loop. */ 35 | def ap[A,B](a: A)(f: A => B): B = { 36 | var ai: Any = a 37 | var fi: Any => Any = f.asInstanceOf[Any => Any] 38 | while (true) { 39 | try return fi(ai).asInstanceOf[B] 40 | catch { case Call(a2,f2) => ai = a2; fi = f2; } 41 | } 42 | return null.asInstanceOf[B] // unreachable 43 | } 44 | 45 | /* Convenience function for forcing a thunk. */ 46 | def force[A](f: () => A): A = 47 | ap(f)(f => f()) 48 | 49 | def more[A](a: => Throw[A]): Throw[A] = More(() => a) 50 | 51 | /* `Throw` forms a `Monad`. */ 52 | 53 | def unit[A](a: => A): Throw[A] = more(Done(a)) 54 | 55 | def flatMap[A,B](a: Throw[A])(f: A => Throw[B]): Throw[B] = 56 | a match { 57 | case Done(a) => f(a) 58 | case More(thunk) => 59 | try thunk() flatMap f 60 | catch { case Call(a0,g) => more { 61 | defer(a0)(g.asInstanceOf[Any => Throw[A]]. 62 | andThen(_ flatMap f)) 63 | }} 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /exercises/src/main/scala/fpinscala/laziness/Stream.scala: -------------------------------------------------------------------------------- 1 | package fpinscala.laziness 2 | 3 | import Stream._ 4 | trait Stream[+A] { 5 | 6 | def foldRight[B](z: => B)(f: (A, => B) => B): B = // The arrow `=>` in front of the argument type `B` means that the function `f` takes its second argument by name and may choose not to evaluate it. 7 | this match { 8 | case Cons(h,t) => f(h(), t().foldRight(z)(f)) // If `f` doesn't evaluate its second argument, the recursion never occurs. 9 | case _ => z 10 | } 11 | 12 | def exists(p: A => Boolean): Boolean = 13 | foldRight(false)((a, b) => p(a) || b) // Here `b` is the unevaluated recursive step that folds the tail of the stream. If `p(a)` returns `true`, `b` will never be evaluated and the computation terminates early. 14 | 15 | @annotation.tailrec 16 | final def find(f: A => Boolean): Option[A] = this match { 17 | case Empty => None 18 | case Cons(h, t) => if (f(h())) Some(h()) else t().find(f) 19 | } 20 | def take(n: Int): Stream[A] = sys.error("todo") 21 | 22 | def drop(n: Int): Stream[A] = sys.error("todo") 23 | 24 | def takeWhile(p: A => Boolean): Stream[A] = sys.error("todo") 25 | 26 | def forAll(p: A => Boolean): Boolean = sys.error("todo") 27 | 28 | def headOption: Option[A] = sys.error("todo") 29 | 30 | // 5.7 map, filter, append, flatmap using foldRight. Part of the exercise is 31 | // writing your own function signatures. 32 | 33 | def startsWith[B](s: Stream[B]): Boolean = sys.error("todo") 34 | } 35 | case object Empty extends Stream[Nothing] 36 | case class Cons[+A](h: () => A, t: () => Stream[A]) extends Stream[A] 37 | 38 | object Stream { 39 | def cons[A](hd: => A, tl: => Stream[A]): Stream[A] = { 40 | lazy val head = hd 41 | lazy val tail = tl 42 | Cons(() => head, () => tail) 43 | } 44 | 45 | def empty[A]: Stream[A] = Empty 46 | 47 | def apply[A](as: A*): Stream[A] = 48 | if (as.isEmpty) empty 49 | else cons(as.head, apply(as.tail: _*)) 50 | 51 | val ones: Stream[Int] = Stream.cons(1, ones) 52 | def from(n: Int): Stream[Int] = sys.error("todo") 53 | 54 | def unfold[A, S](z: S)(f: S => Option[(A, S)]): Stream[A] = sys.error("todo") 55 | } -------------------------------------------------------------------------------- /exercises/src/main/scala/fpinscala/iomonad/Task.scala: -------------------------------------------------------------------------------- 1 | package fpinscala.iomonad 2 | 3 | import fpinscala.parallelism.Nonblocking._ 4 | import java.util.concurrent.ExecutorService 5 | 6 | /* 7 | * `Task[A]` is a wrapper around `Free[Par, Either[Throwable, A]]`, with some 8 | * convenience functions for handling exceptions. 9 | */ 10 | case class Task[A](get: IO[Either[Throwable, A]]) { 11 | 12 | def flatMap[B](f: A => Task[B]): Task[B] = 13 | Task(get.flatMap { 14 | case Left(e) => IO(Left(e)) 15 | case Right(a) => f(a).get 16 | }) 17 | 18 | def map[B](f: A => B): Task[B] = flatMap(f andThen (Task.now)) 19 | 20 | /* 'Catches' exceptions in the given task and returns them as values. */ 21 | def attempt: Task[Either[Throwable,A]] = 22 | Task(get map { 23 | case Left(e) => Right(Left(e)) 24 | case Right(a) => Right(Right(a)) 25 | }) 26 | 27 | def handle[B>:A](f: PartialFunction[Throwable,B]): Task[B] = 28 | attempt flatMap { 29 | case Left(e) => f.lift(e) map (Task.now) getOrElse Task.fail(e) 30 | case Right(a) => Task.now(a) 31 | } 32 | 33 | def or[B>:A](t2: Task[B]): Task[B] = 34 | Task(this.get flatMap { 35 | case Left(e) => t2.get 36 | case a => IO(a) 37 | }) 38 | 39 | def run(implicit E: ExecutorService): A = unsafePerformIO(get) match { 40 | case Left(e) => throw e 41 | case Right(a) => a 42 | } 43 | 44 | def attemptRun(implicit E: ExecutorService): Either[Throwable,A] = 45 | try unsafePerformIO(get) catch { case t: Throwable => Left(t) } 46 | } 47 | 48 | object Task extends Monad[Task] { 49 | def unit[A](a: => A) = Task(IO(Try(a))) 50 | 51 | def flatMap[A,B](a: Task[A])(f: A => Task[B]): Task[B] = 52 | a flatMap f 53 | 54 | def fail[A](e: Throwable): Task[A] = Task(IO(Left(e))) 55 | def now[A](a: A): Task[A] = Task(Return(Right(a))) 56 | 57 | def more[A](a: => Task[A]): Task[A] = Task.now(()) flatMap (_ => a) 58 | 59 | def delay[A](a: => A): Task[A] = more(now(a)) 60 | def fork[A](a: => Task[A]): Task[A] = 61 | Task { par { Par.lazyUnit(()) } flatMap (_ => a.get) } 62 | def forkUnit[A](a: => A): Task[A] = fork(now(a)) 63 | 64 | def Try[A](a: => A): Either[Throwable,A] = 65 | try Right(a) catch { case e: Throwable => Left(e) } 66 | } 67 | -------------------------------------------------------------------------------- /answers/src/main/scala/fpinscala/iomonad/Task.scala: -------------------------------------------------------------------------------- 1 | package fpinscala.iomonad 2 | 3 | import fpinscala.parallelism.Nonblocking._ 4 | import java.util.concurrent.ExecutorService 5 | 6 | /* 7 | * `Task[A]` is a wrapper around `Free[Par, Either[Throwable, A]]`, with some 8 | * convenience functions for handling exceptions. 9 | */ 10 | case class Task[A](get: IO[Either[Throwable, A]]) { 11 | 12 | def flatMap[B](f: A => Task[B]): Task[B] = 13 | Task(get.flatMap { 14 | case Left(e) => IO(Left(e)) 15 | case Right(a) => f(a).get 16 | }) 17 | 18 | def map[B](f: A => B): Task[B] = flatMap(f andThen (Task.now)) 19 | 20 | /* 'Catches' exceptions in the given task and returns them as values. */ 21 | def attempt: Task[Either[Throwable,A]] = 22 | Task(get map { 23 | case Left(e) => Right(Left(e)) 24 | case Right(a) => Right(Right(a)) 25 | }) 26 | 27 | def handle[B>:A](f: PartialFunction[Throwable,B]): Task[B] = 28 | attempt flatMap { 29 | case Left(e) => f.lift(e) map (Task.now) getOrElse Task.fail(e) 30 | case Right(a) => Task.now(a) 31 | } 32 | 33 | def or[B>:A](t2: Task[B]): Task[B] = 34 | Task(this.get flatMap { 35 | case Left(e) => t2.get 36 | case a => IO(a) 37 | }) 38 | 39 | def run(implicit E: ExecutorService): A = unsafePerformIO(get) match { 40 | case Left(e) => throw e 41 | case Right(a) => a 42 | } 43 | 44 | def attemptRun(implicit E: ExecutorService): Either[Throwable,A] = 45 | try unsafePerformIO(get) catch { case t: Throwable => Left(t) } 46 | } 47 | 48 | object Task extends Monad[Task] { 49 | def unit[A](a: => A) = Task(IO(Try(a))) 50 | 51 | def flatMap[A,B](a: Task[A])(f: A => Task[B]): Task[B] = 52 | a flatMap f 53 | 54 | def fail[A](e: Throwable): Task[A] = Task(IO(Left(e))) 55 | def now[A](a: A): Task[A] = Task(Return(Right(a))) 56 | 57 | def more[A](a: => Task[A]): Task[A] = Task.now(()) flatMap (_ => a) 58 | 59 | def delay[A](a: => A): Task[A] = more(now(a)) 60 | def fork[A](a: => Task[A]): Task[A] = 61 | Task { par { Par.lazyUnit(()) } flatMap (_ => a.get) } 62 | def forkUnit[A](a: => A): Task[A] = fork(now(a)) 63 | 64 | def Try[A](a: => A): Either[Throwable,A] = 65 | try Right(a) catch { case e: Throwable => Left(e) } 66 | } 67 | 68 | -------------------------------------------------------------------------------- /answerkey/monads/14.answer.scala: -------------------------------------------------------------------------------- 1 | We can look at the associative law in terms of `flatMap` from another perspective. It says that `x.flatMap(f).flatMap(g)` is equal to `x.flatMap(a => f(a).flatMap(g))` _for all_ choices of `f` and `g`. So let's pick a particular `f` and `g` that's easy to think about. We can just pick the identity function: 2 | 3 | x.flatMap(z => z).flatMap(z => z) == x.flatMap(a => a.flatMap(z => z)) 4 | 5 | And of course, flatMapping with the identify function is `join`! The associative law can now be stated as: 6 | 7 | join(join(x)) == x.flatMap(join) 8 | 9 | And we know that `flatMap` is "map, then join," so let's eliminate this last call to `flatMap`: 10 | 11 | join(join(x)) == join(map(x)(join)) 12 | 13 | The identity laws in terms of `join` are: 14 | 15 | join(map(x)(unit)) == x 16 | join(unit(x)) == x 17 | 18 | This follows from the definition of `join` and the identity laws in terms of `flatMap`: 19 | 20 | flatMap(x)(unit) == x 21 | flatMap(unit(x))(f) == f(x) 22 | 23 | For the second law, we simply substitute the identity function for `f`, which gives us `join`. 24 | 25 | Let's make a fast-and-loose proof for this version of the associative law using the `List` monad as an example. Of course, `join` in the `List` monad is just _list concatenation_: 26 | 27 | scala> listMonad.join(List(List(1, 2), List(3, 4))) 28 | res0: List[Int] = List(1, 2, 3, 4) 29 | 30 | Now let's say we have some lists, nested to a depth of three: 31 | 32 | val ns: List[List[List[Int]]] = 33 | List(List(List(1,2), List(3,4)), 34 | List(List(), List(5))) 35 | 36 | If we `join` this list, the outer lists get concatenated and we have a list of lists two levels deep: 37 | 38 | scala> ns.flatten 39 | res1: List[List[Int]] = List(List(1, 2), List(3, 4), List(), List(5)) 40 | 41 | If we instead _map_ `join` over it, we get a different nesting but again two levels deep. This flattens the _inner_ lists. 42 | 43 | scala> ns.map(listMonad.join) 44 | res2: List[List[Int]] = List(List(1, 2, 3, 4), List(5)) 45 | 46 | And then joining `res1` should be the same as joining `res2`: 47 | 48 | scala> listMonad.join(res1) == listMonad.join(res2) 49 | res3: Boolean = true 50 | 51 | So all that the associative law is saying for the `List` monad is that concatenating the outer lists and then the inner ones (`join(join(ns))`) is the same as first concatenating the inner lists and then the outer ones (`join(ns.map(join))`). -------------------------------------------------------------------------------- /answerkey/state/10.answer.scala: -------------------------------------------------------------------------------- 1 | case class State[S, +A](run: S => (A, S)) { 2 | def map[B](f: A => B): State[S, B] = 3 | flatMap(a => unit(f(a))) 4 | def map2[B,C](sb: State[S, B])(f: (A, B) => C): State[S, C] = 5 | flatMap(a => sb.map(b => f(a, b))) 6 | def flatMap[B](f: A => State[S, B]): State[S, B] = State(s => { 7 | val (a, s1) = run(s) 8 | f(a).run(s1) 9 | }) 10 | } 11 | 12 | object State { 13 | 14 | def unit[S, A](a: A): State[S, A] = 15 | State(s => (a, s)) 16 | 17 | // The idiomatic solution is expressed via foldRight 18 | def sequenceViaFoldRight[S,A](sas: List[State[S, A]]): State[S, List[A]] = 19 | sas.foldRight(unit[S, List[A]](List()))((f, acc) => f.map2(acc)(_ :: _)) 20 | 21 | // This implementation uses a loop internally and is the same recursion 22 | // pattern as a left fold. It is quite common with left folds to build 23 | // up a list in reverse order, then reverse it at the end. 24 | // (We could also use a collection.mutable.ListBuffer internally.) 25 | def sequence[S, A](sas: List[State[S, A]]): State[S, List[A]] = { 26 | def go(s: S, actions: List[State[S,A]], acc: List[A]): (List[A],S) = 27 | actions match { 28 | case Nil => (acc.reverse,s) 29 | case h :: t => h.run(s) match { case (a,s2) => go(s2, t, a :: acc) } 30 | } 31 | State((s: S) => go(s,sas,List())) 32 | } 33 | 34 | // We can also write the loop using a left fold. This is tail recursive like the 35 | // previous solution, but it reverses the list _before_ folding it instead of after. 36 | // You might think that this is slower than the `foldRight` solution since it 37 | // walks over the list twice, but it's actually faster! The `foldRight` solution 38 | // technically has to also walk the list twice, since it has to unravel the call 39 | // stack, not being tail recursive. And the call stack will be as tall as the list 40 | // is long. 41 | def sequenceViaFoldLeft[S,A](l: List[State[S, A]]): State[S, List[A]] = 42 | l.reverse.foldLeft(unit[S, List[A]](List()))((acc, f) => f.map2(acc)( _ :: _ )) 43 | 44 | def modify[S](f: S => S): State[S, Unit] = for { 45 | s <- get // Gets the current state and assigns it to `s`. 46 | _ <- set(f(s)) // Sets the new state to `f` applied to `s`. 47 | } yield () 48 | 49 | def get[S]: State[S, S] = State(s => (s, s)) 50 | 51 | def set[S](s: S): State[S, Unit] = State(_ => ((), s)) 52 | } 53 | -------------------------------------------------------------------------------- /exercises/src/main/scala/fpinscala/state/State.scala: -------------------------------------------------------------------------------- 1 | package fpinscala.state 2 | 3 | 4 | trait RNG { 5 | def nextInt: (Int, RNG) // Should generate a random `Int`. We'll later define other functions in terms of `nextInt`. 6 | } 7 | 8 | object RNG { 9 | // NB - this was called SimpleRNG in the book text 10 | 11 | case class Simple(seed: Long) extends RNG { 12 | def nextInt: (Int, RNG) = { 13 | val newSeed = (seed * 0x5DEECE66DL + 0xBL) & 0xFFFFFFFFFFFFL // `&` is bitwise AND. We use the current seed to generate a new seed. 14 | val nextRNG = Simple(newSeed) // The next state, which is an `RNG` instance created from the new seed. 15 | val n = (newSeed >>> 16).toInt // `>>>` is right binary shift with zero fill. The value `n` is our new pseudo-random integer. 16 | (n, nextRNG) // The return value is a tuple containing both a pseudo-random integer and the next `RNG` state. 17 | } 18 | } 19 | 20 | type Rand[+A] = RNG => (A, RNG) 21 | 22 | val int: Rand[Int] = _.nextInt 23 | 24 | def unit[A](a: A): Rand[A] = 25 | rng => (a, rng) 26 | 27 | def map[A,B](s: Rand[A])(f: A => B): Rand[B] = 28 | rng => { 29 | val (a, rng2) = s(rng) 30 | (f(a), rng2) 31 | } 32 | 33 | def nonNegativeInt(rng: RNG): (Int, RNG) = ??? 34 | 35 | def double(rng: RNG): (Double, RNG) = ??? 36 | 37 | def intDouble(rng: RNG): ((Int,Double), RNG) = ??? 38 | 39 | def doubleInt(rng: RNG): ((Double,Int), RNG) = ??? 40 | 41 | def double3(rng: RNG): ((Double,Double,Double), RNG) = ??? 42 | 43 | def ints(count: Int)(rng: RNG): (List[Int], RNG) = ??? 44 | 45 | def map2[A,B,C](ra: Rand[A], rb: Rand[B])(f: (A, B) => C): Rand[C] = ??? 46 | 47 | def sequence[A](fs: List[Rand[A]]): Rand[List[A]] = ??? 48 | 49 | def flatMap[A,B](f: Rand[A])(g: A => Rand[B]): Rand[B] = ??? 50 | } 51 | 52 | case class State[S,+A](run: S => (A, S)) { 53 | def map[B](f: A => B): State[S, B] = 54 | sys.error("todo") 55 | def map2[B,C](sb: State[S, B])(f: (A, B) => C): State[S, C] = 56 | sys.error("todo") 57 | def flatMap[B](f: A => State[S, B]): State[S, B] = 58 | sys.error("todo") 59 | } 60 | 61 | sealed trait Input 62 | case object Coin extends Input 63 | case object Turn extends Input 64 | 65 | case class Machine(locked: Boolean, candies: Int, coins: Int) 66 | 67 | object State { 68 | type Rand[A] = State[RNG, A] 69 | def simulateMachine(inputs: List[Input]): State[Machine, (Int, Int)] = ??? 70 | } 71 | -------------------------------------------------------------------------------- /answers/src/main/scala/fpinscala/parsing/JSON.scala: -------------------------------------------------------------------------------- 1 | package fpinscala.parsing 2 | 3 | import language.higherKinds 4 | import language.implicitConversions 5 | 6 | trait JSON 7 | 8 | object JSON { 9 | case object JNull extends JSON 10 | case class JNumber(get: Double) extends JSON 11 | case class JString(get: String) extends JSON 12 | case class JBool(get: Boolean) extends JSON 13 | case class JArray(get: IndexedSeq[JSON]) extends JSON 14 | case class JObject(get: Map[String, JSON]) extends JSON 15 | 16 | def jsonParser[Parser[+_]](P: Parsers[Parser]): Parser[JSON] = { 17 | // we'll hide the string implicit conversion and promote strings to tokens instead 18 | // this is a bit nicer than having to write token everywhere 19 | import P.{string => _, _} 20 | implicit def tok(s: String) = token(P.string(s)) 21 | 22 | def array = surround("[","]")( 23 | value sep "," map (vs => JArray(vs.toIndexedSeq))) scope "array" 24 | def obj = surround("{","}")( 25 | keyval sep "," map (kvs => JObject(kvs.toMap))) scope "object" 26 | def keyval = escapedQuoted ** (":" *> value) 27 | def lit = scope("literal") { 28 | "null".as(JNull) | 29 | double.map(JNumber(_)) | 30 | escapedQuoted.map(JString(_)) | 31 | "true".as(JBool(true)) | 32 | "false".as(JBool(false)) 33 | } 34 | def value: Parser[JSON] = lit | obj | array 35 | root(whitespace *> (obj | array)) 36 | } 37 | } 38 | 39 | /** 40 | * JSON parsing example. 41 | */ 42 | object JSONExample extends App { 43 | val jsonTxt = """ 44 | { 45 | "Company name" : "Microsoft Corporation", 46 | "Ticker" : "MSFT", 47 | "Active" : true, 48 | "Price" : 30.66, 49 | "Shares outstanding" : 8.38e9, 50 | "Related companies" : [ "HPQ", "IBM", "YHOO", "DELL", "GOOG" ] 51 | } 52 | """ 53 | 54 | val malformedJson1 = """ 55 | { 56 | "Company name" ; "Microsoft Corporation" 57 | } 58 | """ 59 | 60 | val malformedJson2 = """ 61 | [ 62 | [ "HPQ", "IBM", 63 | "YHOO", "DELL" ++ 64 | "GOOG" 65 | ] 66 | ] 67 | """ 68 | 69 | val P = fpinscala.parsing.Reference 70 | import fpinscala.parsing.ReferenceTypes.Parser 71 | 72 | def printResult[E](e: Either[E,JSON]) = 73 | e.fold(println, println) 74 | 75 | val json: Parser[JSON] = JSON.jsonParser(P) 76 | printResult { P.run(json)(jsonTxt) } 77 | println("--") 78 | printResult { P.run(json)(malformedJson1) } 79 | println("--") 80 | printResult { P.run(json)(malformedJson2) } 81 | } 82 | -------------------------------------------------------------------------------- /exercises/src/main/scala/fpinscala/datastructures/List.scala: -------------------------------------------------------------------------------- 1 | package fpinscala.datastructures 2 | 3 | sealed trait List[+A] // `List` data type, parameterized on a type, `A` 4 | case object Nil extends List[Nothing] // A `List` data constructor representing the empty list 5 | /* Another data constructor, representing nonempty lists. Note that `tail` is another `List[A]`, 6 | which may be `Nil` or another `Cons`. 7 | */ 8 | case class Cons[+A](head: A, tail: List[A]) extends List[A] 9 | 10 | object List { // `List` companion object. Contains functions for creating and working with lists. 11 | def sum(ints: List[Int]): Int = ints match { // A function that uses pattern matching to add up a list of integers 12 | case Nil => 0 // The sum of the empty list is 0. 13 | case Cons(x,xs) => x + sum(xs) // The sum of a list starting with `x` is `x` plus the sum of the rest of the list. 14 | } 15 | 16 | def product(ds: List[Double]): Double = ds match { 17 | case Nil => 1.0 18 | case Cons(0.0, _) => 0.0 19 | case Cons(x,xs) => x * product(xs) 20 | } 21 | 22 | def apply[A](as: A*): List[A] = // Variadic function syntax 23 | if (as.isEmpty) Nil 24 | else Cons(as.head, apply(as.tail: _*)) 25 | 26 | val x = List(1,2,3,4,5) match { 27 | case Cons(x, Cons(2, Cons(4, _))) => x 28 | case Nil => 42 29 | case Cons(x, Cons(y, Cons(3, Cons(4, _)))) => x + y 30 | case Cons(h, t) => h + sum(t) 31 | case _ => 101 32 | } 33 | 34 | def append[A](a1: List[A], a2: List[A]): List[A] = 35 | a1 match { 36 | case Nil => a2 37 | case Cons(h,t) => Cons(h, append(t, a2)) 38 | } 39 | 40 | def foldRight[A,B](as: List[A], z: B)(f: (A, B) => B): B = // Utility functions 41 | as match { 42 | case Nil => z 43 | case Cons(x, xs) => f(x, foldRight(xs, z)(f)) 44 | } 45 | 46 | def sum2(ns: List[Int]) = 47 | foldRight(ns, 0)((x,y) => x + y) 48 | 49 | def product2(ns: List[Double]) = 50 | foldRight(ns, 1.0)(_ * _) // `_ * _` is more concise notation for `(x,y) => x * y`; see sidebar 51 | 52 | 53 | def tail[A](l: List[A]): List[A] = sys.error("todo") 54 | 55 | def setHead[A](l: List[A], h: A): List[A] = sys.error("todo") 56 | 57 | def drop[A](l: List[A], n: Int): List[A] = sys.error("todo") 58 | 59 | def dropWhile[A](l: List[A], f: A => Boolean): List[A] = sys.error("todo") 60 | 61 | def init[A](l: List[A]): List[A] = sys.error("todo") 62 | 63 | def length[A](l: List[A]): Int = sys.error("todo") 64 | 65 | def foldLeft[A,B](l: List[A], z: B)(f: (B, A) => B): B = sys.error("todo") 66 | 67 | def map[A,B](l: List[A])(f: A => B): List[B] = sys.error("todo") 68 | } 69 | -------------------------------------------------------------------------------- /exercises/src/main/scala/fpinscala/monads/Monad.scala: -------------------------------------------------------------------------------- 1 | package fpinscala 2 | package monads 3 | 4 | import parsing._ 5 | import testing._ 6 | import parallelism._ 7 | import state._ 8 | import parallelism.Par._ 9 | import language.higherKinds 10 | 11 | 12 | trait Functor[F[_]] { 13 | def map[A,B](fa: F[A])(f: A => B): F[B] 14 | 15 | def distribute[A,B](fab: F[(A, B)]): (F[A], F[B]) = 16 | (map(fab)(_._1), map(fab)(_._2)) 17 | 18 | def codistribute[A,B](e: Either[F[A], F[B]]): F[Either[A, B]] = e match { 19 | case Left(fa) => map(fa)(Left(_)) 20 | case Right(fb) => map(fb)(Right(_)) 21 | } 22 | } 23 | 24 | object Functor { 25 | val listFunctor = new Functor[List] { 26 | def map[A,B](as: List[A])(f: A => B): List[B] = as map f 27 | } 28 | } 29 | 30 | trait Monad[M[_]] extends Functor[M] { 31 | def unit[A](a: => A): M[A] 32 | def flatMap[A,B](ma: M[A])(f: A => M[B]): M[B] 33 | 34 | def map[A,B](ma: M[A])(f: A => B): M[B] = 35 | flatMap(ma)(a => unit(f(a))) 36 | def map2[A,B,C](ma: M[A], mb: M[B])(f: (A, B) => C): M[C] = 37 | flatMap(ma)(a => map(mb)(b => f(a, b))) 38 | 39 | def sequence[A](lma: List[M[A]]): M[List[A]] = ??? 40 | 41 | def traverse[A,B](la: List[A])(f: A => M[B]): M[List[B]] = ??? 42 | 43 | def replicateM[A](n: Int, ma: M[A]): M[List[A]] = ??? 44 | 45 | def compose[A,B,C](f: A => M[B], g: B => M[C]): A => M[C] = ??? 46 | 47 | // Implement in terms of `compose`: 48 | def _flatMap[A,B](ma: M[A])(f: A => M[B]): M[B] = ??? 49 | 50 | def join[A](mma: M[M[A]]): M[A] = ??? 51 | 52 | // Implement in terms of `join`: 53 | def __flatMap[A,B](ma: M[A])(f: A => M[B]): M[B] = ??? 54 | } 55 | 56 | case class Reader[R, A](run: R => A) 57 | 58 | object Monad { 59 | val genMonad = new Monad[Gen] { 60 | def unit[A](a: => A): Gen[A] = Gen.unit(a) 61 | override def flatMap[A,B](ma: Gen[A])(f: A => Gen[B]): Gen[B] = 62 | ma flatMap f 63 | } 64 | 65 | val parMonad: Monad[Par] = ??? 66 | 67 | def parserMonad[P[+_]](p: Parsers[P]): Monad[P] = ??? 68 | 69 | val optionMonad: Monad[Option] = ??? 70 | 71 | val streamMonad: Monad[Stream] = ??? 72 | 73 | val listMonad: Monad[List] = ??? 74 | 75 | def stateMonad[S] = ??? 76 | 77 | val idMonad: Monad[Id] = ??? 78 | 79 | def readerMonad[R] = ??? 80 | } 81 | 82 | case class Id[A](value: A) { 83 | def map[B](f: A => B): Id[B] = ??? 84 | def flatMap[B](f: A => Id[B]): Id[B] = ??? 85 | } 86 | 87 | object Reader { 88 | def readerMonad[R] = new Monad[({type f[x] = Reader[R,x]})#f] { 89 | def unit[A](a: => A): Reader[R,A] = ??? 90 | override def flatMap[A,B](st: Reader[R,A])(f: A => Reader[R,B]): Reader[R,B] = ??? 91 | } 92 | } 93 | 94 | --------------------------------------------------------------------------------