Permalink
Browse files

Last exercises for chapter 2 of FPinScala

  • Loading branch information...
1 parent 4f12379 commit afdebd698a9d28657c160e69707feff8f464cfeb @jdesiloniz jdesiloniz committed Jul 13, 2016
@@ -145,8 +145,75 @@ object GettingStartedWithFPSection extends FlatSpec with Matchers with org.scala
}
isSorted(Array(1, 3, 5, 7), (x: Int, y: Int) => x > y) shouldBe res0
- isSorted(Array(7, 5, 3, 1), (x: Int, y: Int) => x < y) shouldBe res1
+ isSorted(Array(7, 5, 1, 3), (x: Int, y: Int) => x < y) shouldBe res1
isSorted(Array("Scala", "Exercises"), (x: String, y: String) => x.length > y.length) shouldBe res2
}
+
+ /**
+ * Currying is a transformation which converts a function `f` of two arguments into a function of one argument that
+ * partially applies `f`. Taking into account its signature, there's only one possible implementation that compiles.
+ * Take a look at it:
+ *
+ * {{{
+ * def curry[A,B,C](f: (A, B) => C): A => (B => C) =
+ * a => b => f(a, b)
+ * }}}
+ *
+ * Let's verify if this principle holds true in the following exercise:
+ */
+ def curryAssert(res0: Boolean, res1: Boolean): Unit = {
+ def curry[A,B,C](f: (A, B) => C): A => (B => C) =
+ a => b => f(a, b)
+
+ def f(a: Int, b: Int): Int = a + b
+ def g(a: Int)(b: Int): Int = a + b
+
+ curry(f)(1)(1) == f(1, 1) shouldBe res0
+ curry(f)(1)(1) == g(1)(1) shouldBe res1
+
+ }
+
+ /**
+ * Uncurrying is the reverse transformation of curry. Take a look at its straightforward implementation:
+ * {{{
+ * def uncurry[A,B,C](f: A => B => C): (A, B) => C =
+ * (a, b) => f(a)(b)
+ * }}}
+ *
+ * Check by yourself if this principle holds true in the next exercise:
+ */
+ def uncurryAssert(res0: Boolean, res1: Boolean): Unit = {
+ def uncurry[A,B,C](f: A => B => C): (A, B) => C =
+ (a, b) => f(a)(b)
+
+ def f(a: Int, b: Int): Int = a + b
+ def g(a: Int)(b: Int): Int = a + b
+
+ uncurry(g)(1, 1) == g(1)(1) shouldBe res0
+ uncurry(g)(1, 1) == f(1, 1) shouldBe res1
+ }
+
+ /**
+ * Function composition can be implemented in the same fashion, just by following the types of its signature. In this
+ * case we want to feed the output of one function to the input of another function.
+ *
+ * {{{
+ * def compose[A,B,C](f: B => C, g: A => B): A => C =
+ * a => f(g(a))
+ * }}}
+ *
+ * Finally, let's check how this `compose` function behaves in the following exercise:
+ */
+ def composeAssert(res0: Boolean, res1: Int, res2: Int): Unit = {
+ def compose[A,B,C](f: B => C, g: A => B): A => C =
+ a => f(g(a))
+
+ def f(b: Int): Int = b / 2
+ def g(a: Int): Int = a + 2
+
+ compose(f, g)(0) == compose(g, f)(0) shouldBe res0
+ compose(f, g)(2) shouldBe res1
+ compose(g, f)(2) shouldBe res2
+ }
}
@@ -14,6 +14,18 @@ class GettingStartedWithFPSpec extends Spec with Checkers {
}
def `isSorted asserts` = {
- check(Test.testSuccess(GettingStartedWithFPSection.isSortedAssert _, true :: true :: true :: HNil))
+ check(Test.testSuccess(GettingStartedWithFPSection.isSortedAssert _, true :: false :: true :: HNil))
+ }
+
+ def `currying asserts` = {
+ check(Test.testSuccess(GettingStartedWithFPSection.curryAssert _, true :: true :: HNil))
+ }
+
+ def `uncurrying asserts` = {
+ check(Test.testSuccess(GettingStartedWithFPSection.uncurryAssert _, true :: true :: HNil))
+ }
+
+ def `composing asserts` = {
+ check(Test.testSuccess(GettingStartedWithFPSection.composeAssert _, false :: 2 :: 3 :: HNil))
}
}

0 comments on commit afdebd6

Please sign in to comment.