Last active
May 25, 2024 10:18
-
-
Save dacr/ffdb4e1c653717cbfef6f737509ef97c to your computer and use it in GitHub Desktop.
Playing with monads / published by https://github.com/dacr/code-examples-manager #05e12ec0-33a4-4e0e-bed1-bd734d951a5d/abf15f9c2bcad9fdc6b2d3f69f83add9c42db925
This file contains hidden or 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
// summary : Playing with monads | |
// keywords : scala, monads, pure-functional, pattern, etw, @testable | |
// publish : gist | |
// authors : David Crosson | |
// license : Apache NON-AI License Version 2.0 (https://raw.githubusercontent.com/non-ai-licenses/non-ai-licenses/main/NON-AI-APACHE2) | |
// id : 05e12ec0-33a4-4e0e-bed1-bd734d951a5d | |
// created-on : 2022-01-22T15:13:44+01:00 | |
// managed-by : https://github.com/dacr/code-examples-manager | |
// run-with : scala-cli $file | |
// --------------------- | |
//> using scala "3.4.2" | |
// --------------------- | |
// ------------------------------------------------------------ | |
// Inspired from "A Monads Approach for Beginners, in Scala | Rock the JVM" | |
// https://www.youtube.com/watch?v=d-dy1x33moA | |
// ------------------------------------------------------------ | |
// Some definitions : | |
// - https://www.baeldung.com/scala/monads : | |
// Monads are nothing more than a mechanism to sequence computations around values augmented with some additional feature | |
// - https://en.wikipedia.org/wiki/Monad_(functional_programming) : | |
// A monad is a type that wraps another type and gives some form of quality to the underlying type | |
// - | |
// ------------------------------------------------------------ | |
// A type is a Monad if it has a unit and bind functions and follow 3 composability laws | |
// Functions | |
// - the unit function : to wrap a value inside the monad | |
// - the flatmap (or bind) function : to sequence computations over a value | |
// PROPERTIES | |
// - left identity : Monad(x).flatMap(f) == f(x) | |
// - right identity : Monad(x).flatMap(y => Monad(y)) == Monad(x) | |
// - associativity : Monad(x).flatMap(f).flatMap(g) == Monad(x).flatMap(y => f(y).flatMap(g)) == f(x).flatMap(g) | |
// ------------------------------------------------------------ | |
case class SafeValue[+T](private val hiddenValue: T): // THE UNIT FUNCTION (the constructor) (also CALLED THE PURE FUNCTION) | |
def get: T = synchronized { | |
hiddenValue | |
} | |
def flatMap[S](transformer: T => SafeValue[S]): SafeValue[S] = // THE FLATMAP FUNCTION (also CALLED THE BIND FUNCTION) | |
synchronized { | |
transformer(hiddenValue) | |
} | |
// ------------------------------------------------------- | |
// The ETW pattern - Extract/Transform/Wrap - the legacy/classic pattern | |
val safeMessage = SafeValue("secret") | |
val message = safeMessage.get // EXTRACT | |
val capitalizedMessage = message.capitalize // TRANSFORM | |
val capitalizedSafeMessage = SafeValue( | |
capitalizedMessage // WRAP | |
) | |
// ------------------------------------------------------- | |
println(SafeValue(40d).flatMap(v => SafeValue(v + 2))) | |
println(SafeValue("hello world").flatMap(v => SafeValue(v.capitalize))) | |
// ------------------------------------------------------- | |
def capitalize(str: String): Option[String] = Some(str.capitalize) | |
def spacelize(str: String): Option[String] = Some(str.map(" " + _).mkString) | |
// ------------------------------------------------------- | |
// MONAD LAW 1 : LEFT IDENTITY | |
// SYNTAX1 : Monad(x).flatMap(f) == f(x) | |
// SYNTAX2 : Monad.unit(x).flatMap(f) = f(x) | |
assert(Option("hello").flatMap(capitalize) == capitalize("hello")) | |
// ------------------------------------------------------- | |
// MONAD LAW 2 : RIGHT IDENTITY | |
// SYNTAX1 : Monad(x).flatMap(y => Monad(y)) == Monad(x) | |
// SYNTAX2 : x.flatMap(y => Monad.unit(y)) = x | |
assert(Option("hello").flatMap(x => Option(x)) == Option("hello")) | |
assert(List(1, 2, 3).flatMap(x => List(x)) == List(1, 2, 3)) | |
// ------------------------------------------------------- | |
// MONAD LAW 3 : ASSOCIATIVITY ( or ETW-ETW ) | |
// SYNTAX1 : Monad(x).flatMap(f).flatMap(g) == Monad(x).flatMap(y => f(y).flatMap(g)) == f(x).flatMap(g) (because of LAW1) | |
// SYNTAX2 : x.flatMap(f).flatMap(g) == x.flatMap(y => f(y).flapMap(g)) | |
assert(Option("hello").flatMap(capitalize).flatMap(spacelize) == Option("hello").flatMap(x => capitalize(x).flatMap(spacelize))) | |
assert(Option("hello").flatMap(capitalize).flatMap(spacelize) == capitalize("hello").flatMap(spacelize)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment