Skip to content

Instantly share code, notes, and snippets.

@SergiiVlasiuk
Forked from doriancodes/Lens and other Optics
Created January 27, 2020 10:57
Show Gist options
  • Save SergiiVlasiuk/ae19017b886df252aa69571aadcbaef0 to your computer and use it in GitHub Desktop.
Save SergiiVlasiuk/ae19017b886df252aa69571aadcbaef0 to your computer and use it in GitHub Desktop.
/**
*
* 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