Last active
June 2, 2022 21:20
-
-
Save JoolsF/089952d28ae42bbd42b89370831dcd40 to your computer and use it in GitHub Desktop.
Monoids practical real-world example
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
/* | |
* Modelling business rules using Monoids | |
* https://medium.com/@shashankbaravani/understanding-monoids-using-real-life-examples-6ec3cb349f2f | |
* | |
* Creating business rules, in this case filters, in a wholly composable way such that they can be combined | |
* in arbitrary orders given they fit the definition of Monoids and are associative. | |
* | |
* The crux of the pattern is the List[Cab] => List[Cab] 'Filter' type which allows the composition. | |
*/ | |
object CoolTaxi { | |
class User(val firstName: String, val lastName: String, val custType: String) | |
class Location(val latitue: Double = 0.00, val longitude: Double = 0.00) | |
class Cab(val typ: String, val totalSeats: Int, val seatsAvlbl: Int, | |
val currentLocation: Location, val finalDestination: Location) { | |
def distanceFromHere(here: Location): Double = 0.00 | |
def timeToDrop(here: Location): Long = 0 | |
def isOnPromotion: Boolean = false | |
} | |
class Source() extends Location | |
class Destination() extends Location | |
//encapsulated a ride request | |
class RideRequest(val source: Source, val destination: Destination, val service: String, val seats: Int) | |
// represents a filter function that take a collection of cabs, filters and returns the result | |
type Filter = List[Cab] => List[Cab] | |
/* a simple filter to filter cabs based on source and destination, */ | |
def matchRoutes(source: Source, destination: Destination): Filter = { | |
cabs: List[Cab] => cabs.filter(c => c.finalDestination == destination && isWithinRange(c.currentLocation, source)) | |
} | |
def isWithinRange(cabLoc: Location, myLoc: Location) = true | |
/* a simple filter to filter cabs based on service type - pool, premier, etc, */ | |
def matchClass(typName: String): Filter = { | |
cabs: List[Cab] => cabs.filter(_.typ.equalsIgnoreCase(typName)) | |
} | |
/* a simple filter to filter cabs based on some kind of promotion */ | |
def matchPromotionCabs: Filter = { | |
cabs: List[Cab] => cabs.filter(_.isOnPromotion) | |
} | |
/* a long laborious process of matching the best cabs based on multitude of factors | |
* such as driver ratings, user ratings, co-passenger ratings, traffic conditions, etc | |
* */ | |
def matchSeats(numOfSeats: Int): Filter = { | |
cabs: List[Cab] => cabs.filter(_.seatsAvlbl == numOfSeats) | |
} | |
def matchDistanceToPickUp(here: Location, dis: Double): Filter = { | |
cabs: List[Cab] => cabs.filter(_.distanceFromHere(here) == dis) | |
} | |
def matchTimeToDrop(here: Location, time: Int): Filter = { | |
cabs: List[Cab] => cabs.filter(_.timeToDrop(here) <= time) | |
} | |
} | |
object CabService{ | |
import CoolTaxi._ | |
val MAX_DIST = 4.00 | |
val MAX_TIME_WAIT = 60 | |
/* predfined recipe for implementing abstract notion of convinience; */ | |
def matchConvinience(location: Location): Filter = matchDistanceToPickUp(location, MAX_DIST) andThen matchTimeToDrop(location, MAX_TIME_WAIT) | |
/* more coarse grained filters have been defined based on underlying ones; */ | |
def matchBasic(start:Source, end: Destination): Filter = matchRoutes(start, end) andThen matchClass("basic") | |
def matchPool(start:Source, end: Destination)(seats: Int): Filter = matchRoutes(start, end) andThen matchClass("pool") andThen matchSeats(seats) | |
def matchPremium(start:Source, end: Destination): Filter = matchRoutes(start, end) andThen matchClass("premium") | |
/* more abtstract constructs defined by business needs however the client is not aware of | |
how these constructs are composed to generate final outcomes */ | |
def matchMyDailyCommute(start:Source, end: Destination): Filter = matchPool(start, end)(1) andThen matchConvinience(start) | |
def matchOffersOnWheels(start:Source, end: Destination): Filter = matchPool(start, end)(1) andThen matchPromotionCabs | |
} | |
object SmartOccupancyManager { | |
import CoolTaxi._ | |
import CabService._ | |
import CabService.{matchMyDailyCommute, matchOffersOnWheels} | |
import CoolTaxi.RideRequest | |
/* a non trivial process of fetching cabs from, say, in memory DB based on source and destination */ | |
val cabsFromDB = List[Cab]() | |
def getCabs(start:Source, end: Destination, user: User, request: RideRequest): List[Cab] = { | |
(request.service, request.seats) match { | |
case ("ShareMyCab", seats) => matchPool(start, end)(seats)(cabsFromDB) | |
case ("OffersOnWheels", _) => matchOffersOnWheels(start, end)(cabsFromDB) | |
case ("MyDailyCommute", _) => matchMyDailyCommute(start, end)(cabsFromDB) | |
case _ => cabsFromDB | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment