Last active
January 27, 2020 10:57
-
-
Save doriancodes/89d09435872ee629cc5d6a56e4bb81bb to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* | |
* LENS | |
* | |
* | |
*/ | |
case class Street(name: String, number: Int) | |
case class Address(country: String, city: String, street: Street) | |
val bigStreet = Street("Unter den Linden", 3) | |
val address1 = Address("Germany", "Berlin", bigStreet) | |
case class User(id: Long, address: Address) | |
case class Account(id: Long, user: User, isActive: Boolean) | |
def changeStreetNumber(account: Account, | |
int: Int): Account = | |
account.copy( | |
user = account.user.copy( | |
address = account.user.address.copy( | |
street = account.user.address.street.copy( | |
number = int | |
) | |
) | |
) | |
) | |
val account = Account(1, User(2, address1), true) | |
case class Lens[A, B]( | |
get: A => B, | |
set: (A, B) => A | |
) | |
val streetNumberLens = Lens[Street, Int]( | |
get = _.number, | |
set = (a, b) => a.copy(number = b) | |
) | |
streetNumberLens.get(bigStreet) | |
streetNumberLens.set(bigStreet, 9) | |
//FROM THE BOOK: Functional And Reactive Domain Modeling | |
def compose[Outer, Inner, Value]( | |
outer: Lens[Outer, Inner], | |
inner: Lens[Inner, Value] | |
) = Lens[Outer, Value]( | |
get = outer.get andThen inner.get, | |
set = (obj, value) => outer.set(obj, inner.set(outer.get(obj), value)) | |
) | |
val addressStreetLens = Lens[Address, Street]( | |
get = _.street, | |
set = (a, b) => a.copy(street = b) | |
) | |
val addressStreetNumberLens: Lens[Address, Int] = compose(addressStreetLens, streetNumberLens) | |
/** | |
* | |
* PRISM | |
* | |
*/ | |
sealed trait Pet | |
case class Dog(name: String) extends Pet | |
case class Cat(name: String) extends Pet | |
case object NoPetYet extends Pet | |
//this is a simplification of Prism | |
case class Prism[S, A](_getOption: S => Option[A])( _reverseGet: A => S ){ | |
def getOption(s: S): Option[A] = _getOption(s) | |
def reverseGet(a: A): S = _reverseGet(a) | |
} | |
val petPrism: Prism[Pet, String] = Prism[Pet, String]{ | |
case Dog(n) => Some(n) | |
case _ => None | |
}(name => Dog(name)) | |
petPrism.getOption(Dog("Santa's Little Helper")) | |
petPrism.reverseGet("Santa's Little Helper") | |
/** | |
* | |
* OPTIONAL | |
* | |
*/ | |
//this is a simplification of Optional | |
case class Optional[S, A](_getOption: S => Option[A])(_set: A => S => S){ | |
def getOption(s: S): Option[A] = _getOption(s) | |
def set(a: A): S => S = _set(a) | |
} | |
sealed trait Box | |
case class Present(quantity: Int) extends Box | |
case object NoPresent extends Box | |
val maybePresents = Optional[Box, Int] { | |
case present: Present => Some(present.quantity) | |
case _ => None | |
}{ numberOfPresents => box => box match { | |
case present: Present => present.copy(quantity = numberOfPresents) | |
case _ => box | |
} | |
} | |
maybePresents.getOption(Present(3)) | |
maybePresents.set(9) | |
/** | |
* | |
* LENS LAWS | |
* | |
*/ | |
def getSet[S, A](lens: Lens[S, A], s: S): Boolean = | |
lens.set(s, lens.get(s)) == s | |
def setGet[S, A](lens: Lens[S, A], s: S, a: A): Boolean = | |
lens.get(lens.set(s, a)) == a | |
def putPut[S, A](lens: Lens[S, A], s: S, a: A, b: A): Boolean = | |
lens.get(lens.set(lens.set(s, a), b)) == b | |
val getSetLaw = getSet(streetNumberLens, Street("Pariser Str", 18)) | |
val setGetLaw = setGet(streetNumberLens, Street("Pariser Str", 18), 5) | |
val putPutLaw = putPut(streetNumberLens, Street("Pariser Str", 18), 5, 3) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment