Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Getting Schwifty: Functional Programming with K...

Getting Schwifty: Functional Programming with Kotlin

These are my slides for a talk I've given on 24.08.2017 at the Dutch GDG Android Meetup. https://www.meetup.com/dutch-aug/events/241179303/

Talk intro:
Writing good software is hard, writing bug-free software is next to impossible, but that doesn’t mean that we should never tend to that mythical abstract of `fun` and sustainable code. Add multithreading, state management and a pile of interconnected components to your system and you’ll find that functional programming is your best bet against the vicious spaghetti monster. So, let’s take off… our hats, and get schwifty with Kotlin.

Serj Lotutovici

August 25, 2017
Tweet

More Decks by Serj Lotutovici

Other Decks in Programming

Transcript

  1. Functional Programming? In computer science, functional programming is a programming

    paradigm —that treats computation as the evaluation of mathematical functions and avoids changing-state and mutable data. Wikipedia
  2. Functional Programming? • It’s hard! • Requires a Phd in

    Mathematics! • Can be used only in specific languages!
  3. Functional Programming? • It’s hard! • Requires a Phd in

    Mathematics! • Can be used only in specific languages! • Not every language enforces it. • With Kotlin it’s fun and simple.
  4. Functional Purity • No side effects • Context independent •

    Easy to test • Easy to compose Pure functions (or expressions) have only one purpose and terminate after their execution.
  5. Functional Purity fun pow(value: Int, power: Int): Int { var

    result = 1 repeat(power.abs()) { result *= value } return result }
  6. Functional Purity val pow = { value: Int, power: Int

    -> var result = 1 repeat(power.abs()) { result *= value } result }
  7. Functional Purity val pow = { value: Int, power: Int

    -> logToDb("Random log.") var result = 1 repeat(power.abs()) { result *= value } result }
  8. Functional Purity val pow = { value: Int, power: Int

    -> logToDb("Random log.") var result = 1 repeat(power.abs()) { result *= value } result }
  9. Functional Purity val pow = { value: Int, power: Int

    -> logToDb("Random log.") var result = 1 repeat(power.abs()) { result *= value } result }
  10. Functions as first-class citizens val f = { i: Int

    -> i * 2 } fun foo(f: () -> Unit) fun foo(): () -> Unit fun foo(f: () -> Unit): () -> Unit fun foo() { fun bar() = { } } fun Int.abs() = if (this < 0) this * -1 else this
  11. Recursion • A function that invokes itself • Has one

    (or more) non-recursive returns (preferably ) • Alternative to loops • Warning! May require a stack!
  12. Recursion fun pow(value: Int, power: Int): Int { var result

    = 1 repeat(power.abs()) { result *= value } return result }
  13. Recursion fun Int.pow(power: Int): Int { var result = 1

    repeat(power.abs()) { result *= this } return result }
  14. Recursion fun Int.pow(power: Int): Int { if (power == 0)

    return 1 return this * pow(power - 1) }
  15. Recursion fun Int.pow(power: Int): Int { if (power == 0)

    return 1 return this * pow(power - 1) }
  16. Recursion fun Int.pow(power: Int): Int { if (power == 0)

    return 1 return this * pow(power - 1) }
  17. Recursion fun Int.pow(power: Int): Int { if (power == 0)

    return 1 return this * pow(power - 1) }
  18. Recursion fun Int.pow(power: Int): Int { if (power == 0)

    return 1 return this * pow(power - 1) } So, what about the stack?
  19. Recursion fun pow(value: Int, power: Int, stack: Int): Int {

    if (power == 0) return stack return pow(value, power - 1, stack * value) }
  20. Recursion fun pow(value: Int, power: Int, stack: Int): Int {

    if (power == 0) return stack return pow(value, power - 1, stack * value) }
  21. Recursion fun pow(value: Int, power: Int, stack: Int): Int {

    if (power == 0) return stack return pow(value, power - 1, stack * value) } pow(4, 2, 1)
  22. Recursion fun pow(value: Int, power: Int, stack: Int = 1):

    Int { if (power == 0) return stack return pow(value, power - 1, stack * value) }
  23. Recursion fun pow(value: Int, power: Int, stack: Int = 1):

    Int { if (power == 0) return stack return pow(value, power - 1, stack * value) }
  24. Recursion fun pow(value: Int, power: Int, stack: Int = 1):

    Int { if (power == 0) return stack return pow(value, power - 1, stack * value) }
  25. Recursion fun Int.pow(power: Int): Int { if (power == 0)

    return 1 return this * pow(power - 1) }
  26. Recursion fun Int.pow(power: Int): Int { fun innerPow(value: Int, power:

    Int, stack: Int = 1): Int { if (power == 0) return stack return innerPow(value, power - 1, stack * value) } return innerPow(this, power) }
  27. Recursion fun Int.pow(power: Int): Int { tailrec fun innerPow(value: Int,

    power: Int, stack: Int = 1): Int { if (power == 0) return stack return innerPow(value, power - 1, stack * value) } return innerPow(this, power) }
  28. Recursion fun Int.pow(power: Int): Int { tailrec fun innerPow(value: Int,

    power: Int, stack: Int = 1): Int { if (power == 0) return stack return innerPow(value, power - 1, stack * value) } return innerPow(this, power) }
  29. Recursion // Kotlin fun innerPow(value: Int, power: Int, stack: Int

    = 1): Int { if (power == 0) return stack return innerPow(value, power - 1, stack * value) } // Java public static final int innerPow(int value, int power, int stack) { return power == 0 ? stack : innerPow(value, power - 1, stack * value); }
  30. Recursion // Kotlin tailrec fun innerPow(value: Int, power: Int, stack:

    Int = 1): Int { if (power == 0) return stack return innerPow(value, power - 1, stack * value) } // Java public static final int innerPow(int value, int power, int stack) { while(power != 0) { int var10000 = power - 1; stack *= value; power = var10000; } return stack; }
  31. Immutability sealed class Meeseeks { data class Some(val count: Int)

    : Meeseeks() object None : Meeseeks() } fun more(meeseeks: Meeseeks): Meeseeks { return meeseeks + 1 }
  32. Immutability sealed class Meeseeks { data class Some(val count: Int)

    : Meeseeks() object None : Meeseeks() inline fun map(f: (Int) -> Int): Meeseeks = when (this) { is Some -> Some(f(count)) is None -> this } }
  33. Immutability sealed class Meeseeks { data class Some(val count: Int)

    : Meeseeks() object None : Meeseeks() inline fun map(f: (Int) -> Int): Meeseeks = when (this) { is Some -> Some(f(count)) is None -> this } }
  34. Immutability sealed class Meeseeks { data class Some(val count: Int)

    : Meeseeks() object None : Meeseeks() inline fun map(f: (Int) -> Int): Meeseeks = when (this) { is Some -> Some(f(count)) is None -> this } }
  35. Immutability sealed class Meeseeks { data class Some(val count: Int)

    : Meeseeks() object None : Meeseeks() inline fun map(f: (Int) -> Int): Meeseeks = when (this) { is Some -> Some(f(count)) is None -> this } }
  36. Immutability sealed class Meeseeks { data class Some(val count: Int)

    : Meeseeks() object None : Meeseeks() inline fun map(f: (Int) -> Int): Meeseeks = when (this) { is Some -> Some(f(count)) is None -> this } } `map` - is a functor: • Applies only to un-wrapped values. • Allows for data mutation in a safe way (via unboxing)
  37. Immutability sealed class Meeseeks { data class Some(val count: Int)

    : Meeseeks() object None : Meeseeks() inline fun map(f: (Int) -> Int): Meeseeks = when (this) { is Some -> Some(f(count)) is None -> this } } fun more(meeseeks: Meeseeks): Meeseeks = meeseeks.map { it * 2 }
  38. Immutability sealed class Meeseeks { data class Some(val count: Int)

    : Meeseeks() object None : Meeseeks() inline fun map(f: (Int) -> Int): Meeseeks = when (this) { is Some -> Some(f(count)) is None -> this } } fun more(meeseeks: Meeseeks): Meeseeks = meeseeks.map { it * 2 } more(Meeseeks.Some(2)) // Meeseeks.Some(4) more(Meeseeks.None) // Meeseeks.None
  39. Immutability sealed class Meeseeks { data class Some(val count: Int)

    : Meeseeks() object None : Meeseeks() inline fun map(f: (Int) -> Int): Meeseeks = when (this) { is Some -> Some(f(count)) is None -> this } inline fun flatMap(f: (Int) -> Meeseeks): Meeseeks = when (this) { is Some -> f(count) is None -> None } }
  40. Immutability sealed class Meeseeks { data class Some(val count: Int)

    : Meeseeks() object None : Meeseeks() inline fun map(f: (Int) -> Int): Meeseeks = when (this) { is Some -> Some(f(count)) is None -> this } inline fun flatMap(f: (Int) -> Meeseeks): Meeseeks = when (this) { is Some -> f(count) is None -> None } } `flatMap` - is a monad attribute: • Monads cary functions that apply to wrapped values. • Allows for data mutation in a safe way (via unboxing)
  41. Immutability sealed class Meeseeks { data class Some(val count: Int)

    : Meeseeks() object None : Meeseeks() inline fun map(f: (Int) -> Int): Meeseeks = when (this) { is Some -> Some(f(count)) is None -> this } inline fun flatMap(f: (Int) -> Meeseeks): Meeseeks = when (this) { is Some -> f(count) is None -> None } } fun evenMore(meeseeks: Meeseeks): Meeseeks = meeseeks.flatMap { Meeseeks.Some(it * 3) }
  42. Immutability sealed class Meeseeks { data class Some(val count: Int)

    : Meeseeks() object None : Meeseeks() inline fun map(f: (Int) -> Int): Meeseeks = when (this) { is Some -> Some(f(count)) is None -> this } inline fun flatMap(f: (Int) -> Meeseeks): Meeseeks = when (this) { is Some -> f(count) is None -> None } } fun evenMore(meeseeks: Meeseeks): Meeseeks = meeseeks.flatMap { Meeseeks.Some(it * 3) } evenMore(Meeseeks.Some(2)) // Meeseeks.Some(6) evenMore(Meeseeks.None) // Meeseeks.None
  43. Takeways • Start using Kotlin today • Keep your functions

    pure • Keep your data immutable • Be schwifty! • Read @Aballano posts on Functors, Applicative’s and Monads • Profit