SlideShare une entreprise Scribd logo
1  sur  49
Télécharger pour lire hors ligne
Mining Functional Patterns
Debasish Ghosh
@debasishg
Plan today ..
• Design Pattern

• Algebra

• Algebra <=> Functional Patterns

• Mining patterns on real world Scala code
Code ahead .. Scala code ..
.. though the principles apply
equally well to any statically typed
functional programming language ..
Solution to a Problem in Context
Design Pattern
Solution to a Problem in Context
Design Pattern
Solution to a Problem in Context
Design Pattern
Solution to a Problem in Context
Design Pattern
Solution to a Problem in Context
Design Pattern
we are given a problemgeneric component
(invariant across
context of application)
context dependent
(varies with the
context of problem)
What is an Algebra ?
Algebra is the study of algebraic structures
In mathematics, and more specifically in abstract algebra,
an algebraic structure is a set (called carrier
set or underlying set) with one or more finitary
operations defined on it that satisfies a list of axioms
- Wikipedia
(https://en.wikipedia.org/wiki/Algebraic_structure)
Set A
ϕ : A × A → A
for (a, b) ∈ A
ϕ(a, b)
a ϕ b
given
a binary operation
for specific a, b
or
The Algebra of Sets
3 + 2 = 5
7 + 4 = 11
2 + 0 = 2
0 + 6 = 6
8 + 9 = 9 + 8.
Binary operation
Identity operation
Associative operation
always produces an integer
(closure of operations)
One specific instance of the Algebra
Set A
ϕ : A × A → A
given
a binary operation
(a ϕ b) ϕ c = a ϕ (b ϕ c)
associative
for (a, b, c) ∈ A
Let’s enhance the Algebra ..
Set A
ϕ : A × A → A
given
a binary operation
(a ϕ b) ϕ c = a ϕ (b ϕ c)
associative
for (a, b, c) ∈ A
The Algebra of Semigroups
Set A
ϕ : A × A → A
given
a binary operation
(a ϕ b) ϕ c = a ϕ (b ϕ c)
associative
for (a, b, c) ∈ A
a ϕ I = I ϕ a = a
for (a, I ) ∈ A
identity
The Algebra of Monoids
Algebra <=> Protocol
class Monoid a where
mempty :: a
mappend :: a -> a -> a
Algebra <=> Protocol with Laws
class Monoid a where
mempty :: a
mappend :: a -> a -> a
-- Identity laws
x <> mempty = x
mempty <> x = x
-- Associativity
(x <> y) <> z = x <> (y <> z)
Monoid In Scala
trait Semigroup[A] {
def combine(x: A, y: A): A
}
trait Monoid[A] extends Semigroup[A] {
def empty: A
}
Monoid In Scala
trait Semigroup[A] {
def combine(x: A, y: A): A
}
trait Monoid[A] extends Semigroup[A] {
def empty: A
}
val intAdditionMonoid: Monoid[Int] = new Monoid[Int] {
def empty: Int = 0
def combine(x: Int, y: Int): Int = x + y
}
• algebra (interface)
• reusable
• polymorphic
• standard library code
• instance (implementation)
• specific for a datatype
val moneyAdditionMonoid: Monoid[Money] = new Monoid[Money] {
def empty: Money = ???
def combine(x: Money, y: Money): Money = ???
}
• domain specific instance
• specific for Money
• application library code
Monoid In Scala
trait Semigroup[A] {
def combine(x: A, y: A): A
}
trait Monoid[A] extends Semigroup[A] {
def empty: A
}
val intAdditionMonoid: Monoid[Int] = new Monoid[Int] {
def empty: Int = 0
def combine(x: Int, y: Int): Int = x + y
}
• algebra (interface)
• reusable
• polymorphic
• standard library code
• instance (implementation)
• specific for a datatype
val moneyAdditionMonoid: Monoid[Money] = new Monoid[Money] {
def empty: Money = ???
def combine(x: Money, y: Money): Money = ???
}
• domain specific instance
• specific for Money
• application library code
Generic
Specific
• Specific implementations
use the generic protocol/interface
• This reusability is enforced by
parametricity (no type specific info
in the protocol)
• Genericity implies reusability
Monoid In Scala
trait Semigroup[A] {
def combine(x: A, y: A): A
}
trait Monoid[A] extends Semigroup[A] {
def empty: A
}
val intAdditionMonoid: Monoid[Int] = new Monoid[Int] {
def empty: Int = 0
def combine(x: Int, y: Int): Int = x + y
}
• algebra (interface)
• reusable
• polymorphic
• standard library code
• instance (implementation)
• specific for a datatype
val moneyAdditionMonoid: Monoid[Money] = new Monoid[Money] {
def empty: Money = ???
def combine(x: Money, y: Money): Money = ???
}
• domain specific instance
• specific for Money
• application library code
Pattern
Instances
generic & reusable
context specific
Functional Patterns
• Generic, reusable algebra
• Parametric on types
• Clear separation between pattern (algebra) and
its instances
• Composable through function composition
Functional Patterns
• Standard vocabulary - people know these terms,
know these operations and their types
• Rich ecosystem support through standard
libraries
• Functions defined in only terms of these
interfaces / algebra can be reused by application
level data types that follow the pattern
Functional Patterns - freebies
• Given a type that has an instance of a Monoid, if we have a
List of such objects, we can combine them for free using
the combine function of Monoid.Also note that the
behavior of combine is completely polymorphic - depends
on the instance of Monoid that you pass in.
• Given a typeV that has an instance of a Monoid, Map[K,
V] also gets a Monoid. Part of standard library, but as an
application developer you get this for free.
• .. and there are many such examples ..
Functional Patterns - Multiplicative Power
Money: Monoid
Payment: Monoid
Foo: Monoid
Bar: Monoid
Polymorphic behaviors in the
library that expects a Monoid
Domain Model Types
with Monoid instances
def fold[A](fa: F[A])
(implicit A: Monoid[A]): A = // ..
def foldMap[A, B](fa: F[A])(f: A => B)
(implicit B: Monoid[B]): B = // ..
def foldMapM[G[_], A, B](fa: F[A])
(f: A => G[B])(implicit G: Monad[G], B: Monoid[B]): G[B] = // ..
(multiply)
Domain Model
// a sum type for Currency
sealed trait Currency
case object USD extends Currency
case object AUD extends Currency
case object JPY extends Currency
case object INR extends Currency
// a Money can have denominations in multiple
// currencies
class Money (val items: Map[Currency, BigDecimal]) {
def toBaseCurrency: BigDecimal =
items.foldLeft(BigDecimal(0)) { case (a, (ccy, amount)) =>
a + Money.exchangeRateWithUSD.get(ccy).getOrElse(BigDecimal(1)) * amount
}
def isDebit = toBaseCurrency < 0
}
Domain Model
object Money {
final val zeroMoney =
new Money(Map.empty[Currency, BigDecimal])
// smart constructor
def apply(amount: BigDecimal, ccy: Currency) =
new Money(Map(ccy -> amount))
// concrete implementation: add two Money objects
def add(m: Money, n: Money) = new Money(
(m.items.toList ++ n.items.toList)
.groupBy(_._1)
.map { case (k, v) =>
(k, v.map(_._2).sum)
}
)
// sample implementation
final val exchangeRateWithUSD: Map[Currency, BigDecimal] =
Map(AUD -> 0.76, JPY -> 0.009, INR -> 0.016, USD -> 1.0)
}
concrete implementation
of fusing 2 Maps - can
we generalize it ?
Domain Model
import java.time.OffsetDateTime
// Account with a specific unique account no
case class Account(no: String, name: String, openDate: OffsetDateTime,
closeDate: Option[OffsetDateTime] = None) {
override def equals(o: Any): Boolean = o match {
case Account(`no`, _, _, _) => true
case _ => false
}
override def hashCode() = no. ##
}
// Payment made for a particular Account
case class Payment(account: Account, amount: Money,
dateOfPayment: OffsetDateTime)
Domain Model
import Money._
object Payments {
def creditAmount(p: Payment): Money =
if (p.amount.isDebit) zeroMoney else p.amount
// concrete implementation
def valuation(payments: List[Payment]): Money =
payments.foldLeft(zeroMoney) { (a, e) =>
add(a, creditAmount(e))
}
// concrete implementation that uses concrete methods of List
def maxPayment(payments: List[Payment]): Money =
payments.map(creditAmount).maxBy(_.toBaseCurrency)
// adjust balances and payments
def newBalances(currentBalances: Map[Account, Money],
currentPayments: Map[Account, Money]): Map[Account, Money] = {
// complicated logic that merges the 2 Maps
Map.empty[Account, Money]
}
}
complex implementation
of fusing 2 Maps - can
we generalize it ?
1. similar contract: Is there
any commonality of
behaviors that we can
extract ?
2. both iterate over the
collection and compute
an aggregate
Domain Model
object Money {
final val zeroMoney =
new Money(Map.empty[Currency, BigDecimal])
// smart constructor
def apply(amount: BigDecimal, ccy: Currency) =
new Money(Map(ccy -> amount))
// concrete implementation: add two Money objects
def add(m: Money, n: Money) = new Money(
(m.items.toList ++ n.items.toList)
.groupBy(_._1)
.map { case (k, v) =>
(k, v.map(_._2).sum)
}
)
// sample implementation
final val exchangeRateWithUSD: Map[Currency, BigDecimal] =
Map(AUD -> 0.76, JPY -> 0.009, INR -> 0.016, USD -> 1.0)
}
concrete implementation
of fusing 2 Maps - can
we generalize it ?
Domain Model
object Money {
final val zeroMoney =
new Money(Map.empty[Currency, BigDecimal])
// smart constructor
def apply(amount: BigDecimal, ccy: Currency) =
new Money(Map(ccy -> amount))
// concrete implementation: add two Money objects
def add(m: Money, n: Money) = new Money(
(m.items.toList ++ n.items.toList)
.groupBy(_._1)
.map { case (k, v) =>
(k, v.map(_._2).sum)
}
)
// sample implementation
final val exchangeRateWithUSD: Map[Currency, BigDecimal] =
Map(AUD -> 0.76, JPY -> 0.009, INR -> 0.016, USD -> 1.0)
}
(a) adds 2 Money objects
(b) has to be associative
identity operation
Pattern:
Monoid for Money!
Domain Model
import Money._
object Payments {
def creditAmount(p: Payment): Money =
if (p.amount.isDebit) zeroMoney else p.amount
// concrete implementation
def valuation(payments: List[Payment]): Money =
payments.foldLeft(zeroMoney) { (a, e) =>
add(a, creditAmount(e))
}
// concrete implementation that uses concrete methods of List
def maxPayment(payments: List[Payment]): Money =
payments.map(creditAmount).maxBy(_.toBaseCurrency)
// adjust balances and payments
def newBalances(currentBalances: Map[Account, Money],
currentPayments: Map[Account, Money]): Map[Account, Money] = {
// complicated logic that merges the 2 Maps
Map.empty[Account, Money]
}
}
complex implementation
of fusing 2 Maps - can
we generalize it ?
1. similar contract: Is there
any commonality of
behaviors that we can
extract ?
2. both iterate over the
collection and compute
an aggregate
Domain Model
import Money._
object Payments {
def creditAmount(p: Payment): Money =
if (p.amount.isDebit) zeroMoney else p.amount
// concrete implementation
def valuation(payments: List[Payment]): Money =
payments.foldLeft(zeroMoney) { (a, e) =>
add(a, creditAmount(e))
}
// concrete implementation that uses concrete methods of List
def maxPayment(payments: List[Payment]): Money =
payments.map(creditAmount).maxBy(_.toBaseCurrency)
// adjust balances and payments
def newBalances(currentBalances: Map[Account, Money],
currentPayments: Map[Account, Money]): Map[Account, Money] = {
// complicated logic that merges the 2 Maps
Map.empty[Account, Money]
}
}
2 different ways to combine a
bunch of Money instances
(a) combine to add
(b) combine to find the max
You get a monoid for Map[K, V]
if V has a monoid - part of standard
library.
(a) combine the 2 Maps
Pattern:
Monoid for Money!
Looking Back
• Similar problem
• Different context
• Reuse of the same algebra
• Different concrete instances of the algebra
import Money._
object Payments {
def creditAmount(p: Payment): Money =
if (p.amount.isDebit) zeroMoney else p.amount
// concrete implementation
def valuation(payments: List[Payment]): Money =
payments.foldLeft(zeroMoney) { (a, e) =>
add(a, creditAmount(e))
}
// concrete implementation that uses concrete methods of List
def maxPayment(payments: List[Payment]): Money =
payments.map(creditAmount).maxBy(_.toBaseCurrency)
// adjust balances and payments
def newBalances(currentBalances: Map[Account, Money],
currentPayments: Map[Account, Money]): Map[Account, Money] = {
// complicated logic that merges the 2 Maps
Map.empty[Account, Money]
}
}
Domain Model
• An aggregation that produces
a single result
• Do we really need a List for the
operation that we are doing ?
• Use the least powerful abstraction
that you need
Pattern: Foldable
Abstracting over Structure & Operation
trait Foldable[F[_]] {
def foldleft[A, B](as: F[A], z: B, f: (B, A) => B): B
def foldMap[A, B](as: F[A], f: A => B)(implicit m: Monoid[B]): B =
foldleft(as, m.zero, (b: B, a: A) => m.combine(b, f(a)))
}
def mapReduce[F[_], A, B](as: F[A], f: A => B)
(implicit ff: Foldable[F], m: Monoid[B]) =
ff.foldMap(as, f)
Domain Model
object Payments extends MoneyInstances with Utils {
def creditAmount: Payment => Money = { p =>
if (p.amount.isDebit) zeroMoney else p.amount
}
def valuation(payments: List[Payment]): Money = {
implicit val m: Monoid[Money] = MoneyAddMonoid
mapReduce(payments)(creditAmount)
}
def maxPayment(payments: List[Payment]): Money = {
implicit val m: Monoid[Money] = MoneyOrderMonoid
mapReduce(payments)(creditAmount)
}
def newBalances(currentBalances: Map[Account, Money],
currentPayments: Map[Account, Money]): Map[Account, Money] = {
implicit val m = MoneyAddMonoid
currentBalances |+| currentPayments
}
}
• Completely generic implementation
with Money manipulation logic
moved to the library code
• Reusability FTW
Parametricity
def mapReduce[F[_], A, B](as: F[A], f: A => B)
(implicit ff: Foldable[F], m: Monoid[B]) =
ff.foldMap(as, f)
• Parametric polymorphism
• No dependence on concrete types
• Reusable under multiple implementation context
• Limited implementation possibilities by definition
• Honors the principle of using the least powerful abstraction that works
• The most important virtue of good functional patterns
Domain Model (Handling Domain Validations)
private void validateState() throws ModelCtorException {
ModelCtorException ex = new ModelCtorException();
if (FAILS == Check.optional(fId, Check.range(1,50))) {
ex.add("Id is optional, 1 ..50 chars.");
}
if (FAILS == Check.required(fName, Check.range(2,50))) {
ex.add("Restaurant Name is required, 2 ..50 chars.");
}
if (FAILS == Check.optional(fLocation, Check.range(2,50))) {
ex.add("Location is optional, 2 ..50 chars.");
}
Validator[] priceChecks = {Check.range(ZERO, HUNDRED), Check.numDecimalsAlways(2)};
if (FAILS == Check.optional(fPrice, priceChecks)) {
ex.add("Price is optional, 0.00 to 100.00.");
}
if (FAILS == Check.optional(fComment, Check.range(2,50))) {
ex.add("Comment is optional, 2 ..50 chars.");
}
if ( ! ex.isEmpty() ) throw ex;
}
Domain Model (Managing Configurations)
public Handler getHandler(Config config) throws Exception {
final String defaultTopic = config.getString("default_topic");
boolean propagate = false;
try {
propagate = config.getBoolean("propagate");
} catch (ConfigException.Missing ignored) {
}
if ("null".equals(defaultTopic)) {
log.warn("default topic is "null"; messages will be discarded unless tagged with kt:");
}
final Properties properties = new Properties();
for (Map.Entry<String, ConfigValue> kv : config.getConfig("producer_config").entrySet()) {
properties.put(kv.getKey(), kv.getValue().unwrapped().toString());
}
final String clientId = // ..
// ..
EncryptionConfig encryptionConfig = new EncryptionConfig();
try {
Config encryption = config.getConfig("encryption");
encryptionConfig.encryptionKey = encryption.getString("key");
encryptionConfig.encryptionAlgorithm = encryption.getString("algorithm");
encryptionConfig.encryptionTransformation = encryption.getString("transformation");
encryptionConfig.encryptionProvider = encryption.getString("provider");
} catch (ConfigException.Missing ignored) {
encryptionConfig = null;
}
return new KafkaHandler(clientId, propagate, defaultTopic, producer, encryptionConfig);
}
Antipatterns
• Repetition
• Imperative, not expression based - hence not
composable
• Littered with exception handling code (try/catch) -
violates referential transparency
• Not modular
Domain Model
type ErrorOr[A] = Either[Exception, A]
private def readString(path: String, config: Config): ErrorOr[String] = try {
Either.right(config.getString(path))
} catch {
case ex: Exception => Either.left(ex)
} Step 1: Abstract exceptions with
an algebra. We need to handle
exceptions, but not throw it upstream
case class KafkaSettings(
brokers: String,
zk: String,
fromTopic: String,
toTopic: String,
errorTopic: String
)
Step 2: Use an algebraic data type
for configuration information
Domain Model
type ErrorOr[A] = Either[Exception, A]
private def readString(path: String, config: Config): ErrorOr[String] = try {
Either.right(config.getString(path))
} catch {
case ex: Exception => Either.left(ex)
}
import com.typesafe.config.Config
def fromKafkaConfig(config: Config) = for {
b <- readString("dcos.kafka.brokers", config)
z <- readString("dcos.kafka.zookeeper", config)
f <- readString("dcos.kafka.fromtopic", config)
t <- readString("dcos.kafka.totopic", config)
e <- readString("dcos.kafka.errortopic", config)
} yield KafkaSettings(b, z, f, t, e)
• Algebra of Monad for composition
of readString
• Looks imperative (and hence intuitive)
though in reality it’s an expression
• Reusing algebra and defining implementation
specific context
Domain Model
import com.typesafe.config.Config
def fromKafkaConfig(config: Config): ErrorOr[KafkaSettings] = for {
b <- readString("dcos.kafka.brokers", config)
z <- readString("dcos.kafka.zookeeper", config)
f <- readString("dcos.kafka.fromtopic", config)
t <- readString("dcos.kafka.totopic", config)
e <- readString("dcos.kafka.errortopic", config)
} yield KafkaSettings(b, z, f, t, e)
Repetitions ..
Algebraic Composition
def fromKafkaConfig(config: Config): ErrorOr[KafkaSettings] = for {
b <- readString("dcos.kafka.brokers", config)
z <- readString("dcos.kafka.zookeeper", config)
f <- readString("dcos.kafka.fromtopic", config)
t <- readString("dcos.kafka.totopic", config)
e <- readString("dcos.kafka.errortopic", config)
} yield KafkaSettings(b, z, f, t, e)
Either[Exception, KafkaSettings]
Algebraic Composition
Either[Exception, KafkaSettings]Config =>
def fromKafkaConfig: Config => ErrorOr[KafkaSettings] = (config: Config) => for {
b <- readString("dcos.kafka.brokers", config)
z <- readString("dcos.kafka.zookeeper", config)
f <- readString("dcos.kafka.fromtopic", config)
t <- readString("dcos.kafka.totopic", config)
e <- readString("dcos.kafka.errortopic", config)
} yield KafkaSettings(b, z, f, t, e)
ReaderT[ErrorOr, Config, KafkaSettings]
we want a better abstraction
for reading stuff in
the abstraction needs to
compose with Either
Algebraic Composition
Either[Exception, KafkaSettings]Config =>
def fromKafkaConfig: Config => ErrorOr[KafkaSettings] = (config: Config) => for {
b <- readString("dcos.kafka.brokers", config)
z <- readString("dcos.kafka.zookeeper", config)
f <- readString("dcos.kafka.fromtopic", config)
t <- readString("dcos.kafka.totopic", config)
e <- readString("dcos.kafka.errortopic", config)
} yield KafkaSettings(b, z, f, t, e)
ReaderT[ErrorOr, Config, KafkaSettings]
• An algebra abstracting our earlier
expression
• Does 2 things - the Reader monad
wraps a unary function & the T part
indicating a monad transformer composes
the 2 monads, the Reader and the Either
• ReaderT is also a monad
Algebraic Composition
type ConfigReader[A] = ReaderT[ErrorOr, Config, A]
def fromKafkaConfig: ConfigReader[KafkaSettings] = for {
b <- readString("dcos.kafka.brokers")
z <- readString("dcos.kafka.zookeeper")
f <- readString("dcos.kafka.fromtopic")
t <- readString("dcos.kafka.totopic")
e <- readString("dcos.kafka.errortopic")
} yield KafkaSettings(b, z, f, t, e)
def readString(path: String): ConfigReader[String] =
Kleisli { (config: Config) =>
try {
Either.right(config.getString(path))
} catch {
case ex: Exception => Either.left(ex)
}
}
Functional Patterns
• Reuse of already existing algebra (Reader, Monad,
Either etc.)
• Algebraic composition - form larger patterns from
smaller ones
• Abstraction remains composable
• And modular
Thanks!

Contenu connexe

Tendances

Oh, All the things you'll traverse
Oh, All the things you'll traverseOh, All the things you'll traverse
Oh, All the things you'll traverseLuka Jacobowitz
 
Functional and Event Driven - another approach to domain modeling
Functional and Event Driven - another approach to domain modelingFunctional and Event Driven - another approach to domain modeling
Functional and Event Driven - another approach to domain modelingDebasish Ghosh
 
Testing in the World of Functional Programming
Testing in the World of Functional ProgrammingTesting in the World of Functional Programming
Testing in the World of Functional ProgrammingLuka Jacobowitz
 
From functional to Reactive - patterns in domain modeling
From functional to Reactive - patterns in domain modelingFrom functional to Reactive - patterns in domain modeling
From functional to Reactive - patterns in domain modelingDebasish Ghosh
 
Introduction to Functional Programming in JavaScript
Introduction to Functional Programming in JavaScriptIntroduction to Functional Programming in JavaScript
Introduction to Functional Programming in JavaScripttmont
 
Traversals for all ocasions
Traversals for all ocasionsTraversals for all ocasions
Traversals for all ocasionsLuka Jacobowitz
 
Scala categorytheory
Scala categorytheoryScala categorytheory
Scala categorytheoryKnoldus Inc.
 
Intro to Functional Programming
Intro to Functional ProgrammingIntro to Functional Programming
Intro to Functional ProgrammingHugo Firth
 
Functional Programming With Scala
Functional Programming With ScalaFunctional Programming With Scala
Functional Programming With ScalaKnoldus Inc.
 
Type Parameterization
Type ParameterizationType Parameterization
Type ParameterizationKnoldus Inc.
 
Functions In Scala
Functions In Scala Functions In Scala
Functions In Scala Knoldus Inc.
 
constructors and destructors in c++
constructors and destructors in c++constructors and destructors in c++
constructors and destructors in c++HalaiHansaika
 
Monoids, monoids, monoids
Monoids, monoids, monoidsMonoids, monoids, monoids
Monoids, monoids, monoidsLuka Jacobowitz
 
Building a Tagless Final DSL for WebGL
Building a Tagless Final DSL for WebGLBuilding a Tagless Final DSL for WebGL
Building a Tagless Final DSL for WebGLLuka Jacobowitz
 
Effective way to code in Scala
Effective way to code in ScalaEffective way to code in Scala
Effective way to code in ScalaKnoldus Inc.
 
Dependency Injection in Scala - Beyond the Cake Pattern
Dependency Injection in Scala - Beyond the Cake PatternDependency Injection in Scala - Beyond the Cake Pattern
Dependency Injection in Scala - Beyond the Cake PatternDebasish Ghosh
 
Deriving Scalaz
Deriving ScalazDeriving Scalaz
Deriving Scalaznkpart
 
Principled Error Handling with FP
Principled Error Handling with FPPrincipled Error Handling with FP
Principled Error Handling with FPLuka Jacobowitz
 

Tendances (20)

Oh, All the things you'll traverse
Oh, All the things you'll traverseOh, All the things you'll traverse
Oh, All the things you'll traverse
 
Functional and Event Driven - another approach to domain modeling
Functional and Event Driven - another approach to domain modelingFunctional and Event Driven - another approach to domain modeling
Functional and Event Driven - another approach to domain modeling
 
Testing in the World of Functional Programming
Testing in the World of Functional ProgrammingTesting in the World of Functional Programming
Testing in the World of Functional Programming
 
From functional to Reactive - patterns in domain modeling
From functional to Reactive - patterns in domain modelingFrom functional to Reactive - patterns in domain modeling
From functional to Reactive - patterns in domain modeling
 
Introduction to Functional Programming in JavaScript
Introduction to Functional Programming in JavaScriptIntroduction to Functional Programming in JavaScript
Introduction to Functional Programming in JavaScript
 
Traversals for all ocasions
Traversals for all ocasionsTraversals for all ocasions
Traversals for all ocasions
 
Scala categorytheory
Scala categorytheoryScala categorytheory
Scala categorytheory
 
Web futures
Web futuresWeb futures
Web futures
 
Intro to Functional Programming
Intro to Functional ProgrammingIntro to Functional Programming
Intro to Functional Programming
 
Functional Programming With Scala
Functional Programming With ScalaFunctional Programming With Scala
Functional Programming With Scala
 
Clojure basics
Clojure basicsClojure basics
Clojure basics
 
Type Parameterization
Type ParameterizationType Parameterization
Type Parameterization
 
Functions In Scala
Functions In Scala Functions In Scala
Functions In Scala
 
constructors and destructors in c++
constructors and destructors in c++constructors and destructors in c++
constructors and destructors in c++
 
Monoids, monoids, monoids
Monoids, monoids, monoidsMonoids, monoids, monoids
Monoids, monoids, monoids
 
Building a Tagless Final DSL for WebGL
Building a Tagless Final DSL for WebGLBuilding a Tagless Final DSL for WebGL
Building a Tagless Final DSL for WebGL
 
Effective way to code in Scala
Effective way to code in ScalaEffective way to code in Scala
Effective way to code in Scala
 
Dependency Injection in Scala - Beyond the Cake Pattern
Dependency Injection in Scala - Beyond the Cake PatternDependency Injection in Scala - Beyond the Cake Pattern
Dependency Injection in Scala - Beyond the Cake Pattern
 
Deriving Scalaz
Deriving ScalazDeriving Scalaz
Deriving Scalaz
 
Principled Error Handling with FP
Principled Error Handling with FPPrincipled Error Handling with FP
Principled Error Handling with FP
 

En vedette

The Design of the Scalaz 8 Effect System
The Design of the Scalaz 8 Effect SystemThe Design of the Scalaz 8 Effect System
The Design of the Scalaz 8 Effect SystemJohn De Goes
 
Nelson: Rigorous Deployment for a Functional World
Nelson: Rigorous Deployment for a Functional WorldNelson: Rigorous Deployment for a Functional World
Nelson: Rigorous Deployment for a Functional WorldTimothy Perrett
 
Cassandra Fundamentals - C* 2.0
Cassandra Fundamentals - C* 2.0Cassandra Fundamentals - C* 2.0
Cassandra Fundamentals - C* 2.0Russell Spitzer
 
Airbnb - Braavos - Whered My Money Go
Airbnb - Braavos - Whered My Money GoAirbnb - Braavos - Whered My Money Go
Airbnb - Braavos - Whered My Money GoJiang-Ming Yang
 
Real World Serverless
Real World ServerlessReal World Serverless
Real World ServerlessPetr Zapletal
 
Analyzing Functional Programs
Analyzing Functional ProgramsAnalyzing Functional Programs
Analyzing Functional ProgramsDave Cleaver
 
Continuous delivery for machine learning
Continuous delivery for machine learningContinuous delivery for machine learning
Continuous delivery for machine learningRajesh Muppalla
 

En vedette (7)

The Design of the Scalaz 8 Effect System
The Design of the Scalaz 8 Effect SystemThe Design of the Scalaz 8 Effect System
The Design of the Scalaz 8 Effect System
 
Nelson: Rigorous Deployment for a Functional World
Nelson: Rigorous Deployment for a Functional WorldNelson: Rigorous Deployment for a Functional World
Nelson: Rigorous Deployment for a Functional World
 
Cassandra Fundamentals - C* 2.0
Cassandra Fundamentals - C* 2.0Cassandra Fundamentals - C* 2.0
Cassandra Fundamentals - C* 2.0
 
Airbnb - Braavos - Whered My Money Go
Airbnb - Braavos - Whered My Money GoAirbnb - Braavos - Whered My Money Go
Airbnb - Braavos - Whered My Money Go
 
Real World Serverless
Real World ServerlessReal World Serverless
Real World Serverless
 
Analyzing Functional Programs
Analyzing Functional ProgramsAnalyzing Functional Programs
Analyzing Functional Programs
 
Continuous delivery for machine learning
Continuous delivery for machine learningContinuous delivery for machine learning
Continuous delivery for machine learning
 

Similaire à Mining Functional Patterns

Introduction to ad-3.4, an automatic differentiation library in Haskell
Introduction to ad-3.4, an automatic differentiation library in HaskellIntroduction to ad-3.4, an automatic differentiation library in Haskell
Introduction to ad-3.4, an automatic differentiation library in Haskellnebuta
 
Introduction to ad-3.4, an automatic differentiation library in Haskell
Introduction to ad-3.4, an automatic differentiation library in HaskellIntroduction to ad-3.4, an automatic differentiation library in Haskell
Introduction to ad-3.4, an automatic differentiation library in Haskellnebuta
 
Monads and Monoids by Oleksiy Dyagilev
Monads and Monoids by Oleksiy DyagilevMonads and Monoids by Oleksiy Dyagilev
Monads and Monoids by Oleksiy DyagilevJavaDayUA
 
Scala collections wizardry - Scalapeño
Scala collections wizardry - ScalapeñoScala collections wizardry - Scalapeño
Scala collections wizardry - ScalapeñoSagie Davidovich
 
Fuel Up JavaScript with Functional Programming
Fuel Up JavaScript with Functional ProgrammingFuel Up JavaScript with Functional Programming
Fuel Up JavaScript with Functional ProgrammingShine Xavier
 
Functional Programming Patterns for the Pragmatic Programmer
Functional Programming Patterns for the Pragmatic ProgrammerFunctional Programming Patterns for the Pragmatic Programmer
Functional Programming Patterns for the Pragmatic ProgrammerRaúl Raja Martínez
 
List-based Monadic Computations for Dynamic Languages
List-based Monadic Computations for Dynamic LanguagesList-based Monadic Computations for Dynamic Languages
List-based Monadic Computations for Dynamic LanguagesWim Vanderbauwhede
 
High-Performance Haskell
High-Performance HaskellHigh-Performance Haskell
High-Performance HaskellJohan Tibell
 
Functional programming with Scala
Functional programming with ScalaFunctional programming with Scala
Functional programming with ScalaNeelkanth Sachdeva
 
Lecture 5: Functional Programming
Lecture 5: Functional ProgrammingLecture 5: Functional Programming
Lecture 5: Functional ProgrammingEelco Visser
 
From Java to Scala - advantages and possible risks
From Java to Scala - advantages and possible risksFrom Java to Scala - advantages and possible risks
From Java to Scala - advantages and possible risksSeniorDevOnly
 
Scala for Java Programmers
Scala for Java ProgrammersScala for Java Programmers
Scala for Java ProgrammersEric Pederson
 
Ten-page Brief Overview of Swift for Scala Developers
Ten-page Brief Overview of Swift for Scala DevelopersTen-page Brief Overview of Swift for Scala Developers
Ten-page Brief Overview of Swift for Scala Developersihji
 
Principles of functional progrmming in scala
Principles of functional progrmming in scalaPrinciples of functional progrmming in scala
Principles of functional progrmming in scalaehsoon
 

Similaire à Mining Functional Patterns (20)

Introduction to ad-3.4, an automatic differentiation library in Haskell
Introduction to ad-3.4, an automatic differentiation library in HaskellIntroduction to ad-3.4, an automatic differentiation library in Haskell
Introduction to ad-3.4, an automatic differentiation library in Haskell
 
Introduction to ad-3.4, an automatic differentiation library in Haskell
Introduction to ad-3.4, an automatic differentiation library in HaskellIntroduction to ad-3.4, an automatic differentiation library in Haskell
Introduction to ad-3.4, an automatic differentiation library in Haskell
 
Monads and Monoids by Oleksiy Dyagilev
Monads and Monoids by Oleksiy DyagilevMonads and Monoids by Oleksiy Dyagilev
Monads and Monoids by Oleksiy Dyagilev
 
Lecture 3
Lecture 3Lecture 3
Lecture 3
 
Scala collections wizardry - Scalapeño
Scala collections wizardry - ScalapeñoScala collections wizardry - Scalapeño
Scala collections wizardry - Scalapeño
 
Practical cats
Practical catsPractical cats
Practical cats
 
Fuel Up JavaScript with Functional Programming
Fuel Up JavaScript with Functional ProgrammingFuel Up JavaScript with Functional Programming
Fuel Up JavaScript with Functional Programming
 
Functional Programming Patterns for the Pragmatic Programmer
Functional Programming Patterns for the Pragmatic ProgrammerFunctional Programming Patterns for the Pragmatic Programmer
Functional Programming Patterns for the Pragmatic Programmer
 
List-based Monadic Computations for Dynamic Languages
List-based Monadic Computations for Dynamic LanguagesList-based Monadic Computations for Dynamic Languages
List-based Monadic Computations for Dynamic Languages
 
An introduction to scala
An introduction to scalaAn introduction to scala
An introduction to scala
 
Introducing scala
Introducing scalaIntroducing scala
Introducing scala
 
Scala Bootcamp 1
Scala Bootcamp 1Scala Bootcamp 1
Scala Bootcamp 1
 
High-Performance Haskell
High-Performance HaskellHigh-Performance Haskell
High-Performance Haskell
 
Functional programming with Scala
Functional programming with ScalaFunctional programming with Scala
Functional programming with Scala
 
Lecture 5: Functional Programming
Lecture 5: Functional ProgrammingLecture 5: Functional Programming
Lecture 5: Functional Programming
 
From Java to Scala - advantages and possible risks
From Java to Scala - advantages and possible risksFrom Java to Scala - advantages and possible risks
From Java to Scala - advantages and possible risks
 
DSL in scala
DSL in scalaDSL in scala
DSL in scala
 
Scala for Java Programmers
Scala for Java ProgrammersScala for Java Programmers
Scala for Java Programmers
 
Ten-page Brief Overview of Swift for Scala Developers
Ten-page Brief Overview of Swift for Scala DevelopersTen-page Brief Overview of Swift for Scala Developers
Ten-page Brief Overview of Swift for Scala Developers
 
Principles of functional progrmming in scala
Principles of functional progrmming in scalaPrinciples of functional progrmming in scala
Principles of functional progrmming in scala
 

Plus de Debasish Ghosh

Functional Domain Modeling - The ZIO 2 Way
Functional Domain Modeling - The ZIO 2 WayFunctional Domain Modeling - The ZIO 2 Way
Functional Domain Modeling - The ZIO 2 WayDebasish Ghosh
 
Functional and Algebraic Domain Modeling
Functional and Algebraic Domain ModelingFunctional and Algebraic Domain Modeling
Functional and Algebraic Domain ModelingDebasish Ghosh
 
Domain Modeling with Functions - an algebraic approach
Domain Modeling with Functions - an algebraic approachDomain Modeling with Functions - an algebraic approach
Domain Modeling with Functions - an algebraic approachDebasish Ghosh
 
Functional Patterns in Domain Modeling
Functional Patterns in Domain ModelingFunctional Patterns in Domain Modeling
Functional Patterns in Domain ModelingDebasish Ghosh
 
Property based Testing - generative data & executable domain rules
Property based Testing - generative data & executable domain rulesProperty based Testing - generative data & executable domain rules
Property based Testing - generative data & executable domain rulesDebasish Ghosh
 
Big Data - architectural concerns for the new age
Big Data - architectural concerns for the new ageBig Data - architectural concerns for the new age
Big Data - architectural concerns for the new ageDebasish Ghosh
 
Domain Modeling in a Functional World
Domain Modeling in a Functional WorldDomain Modeling in a Functional World
Domain Modeling in a Functional WorldDebasish Ghosh
 
DSL - expressive syntax on top of a clean semantic model
DSL - expressive syntax on top of a clean semantic modelDSL - expressive syntax on top of a clean semantic model
DSL - expressive syntax on top of a clean semantic modelDebasish Ghosh
 

Plus de Debasish Ghosh (8)

Functional Domain Modeling - The ZIO 2 Way
Functional Domain Modeling - The ZIO 2 WayFunctional Domain Modeling - The ZIO 2 Way
Functional Domain Modeling - The ZIO 2 Way
 
Functional and Algebraic Domain Modeling
Functional and Algebraic Domain ModelingFunctional and Algebraic Domain Modeling
Functional and Algebraic Domain Modeling
 
Domain Modeling with Functions - an algebraic approach
Domain Modeling with Functions - an algebraic approachDomain Modeling with Functions - an algebraic approach
Domain Modeling with Functions - an algebraic approach
 
Functional Patterns in Domain Modeling
Functional Patterns in Domain ModelingFunctional Patterns in Domain Modeling
Functional Patterns in Domain Modeling
 
Property based Testing - generative data & executable domain rules
Property based Testing - generative data & executable domain rulesProperty based Testing - generative data & executable domain rules
Property based Testing - generative data & executable domain rules
 
Big Data - architectural concerns for the new age
Big Data - architectural concerns for the new ageBig Data - architectural concerns for the new age
Big Data - architectural concerns for the new age
 
Domain Modeling in a Functional World
Domain Modeling in a Functional WorldDomain Modeling in a Functional World
Domain Modeling in a Functional World
 
DSL - expressive syntax on top of a clean semantic model
DSL - expressive syntax on top of a clean semantic modelDSL - expressive syntax on top of a clean semantic model
DSL - expressive syntax on top of a clean semantic model
 

Dernier

Call Us🔝>༒+91-9711147426⇛Call In girls karol bagh (Delhi)
Call Us🔝>༒+91-9711147426⇛Call In girls karol bagh (Delhi)Call Us🔝>༒+91-9711147426⇛Call In girls karol bagh (Delhi)
Call Us🔝>༒+91-9711147426⇛Call In girls karol bagh (Delhi)jennyeacort
 
Innovate and Collaborate- Harnessing the Power of Open Source Software.pdf
Innovate and Collaborate- Harnessing the Power of Open Source Software.pdfInnovate and Collaborate- Harnessing the Power of Open Source Software.pdf
Innovate and Collaborate- Harnessing the Power of Open Source Software.pdfYashikaSharma391629
 
Sending Calendar Invites on SES and Calendarsnack.pdf
Sending Calendar Invites on SES and Calendarsnack.pdfSending Calendar Invites on SES and Calendarsnack.pdf
Sending Calendar Invites on SES and Calendarsnack.pdf31events.com
 
Balasore Best It Company|| Top 10 IT Company || Balasore Software company Odisha
Balasore Best It Company|| Top 10 IT Company || Balasore Software company OdishaBalasore Best It Company|| Top 10 IT Company || Balasore Software company Odisha
Balasore Best It Company|| Top 10 IT Company || Balasore Software company Odishasmiwainfosol
 
Tech Tuesday - Mastering Time Management Unlock the Power of OnePlan's Timesh...
Tech Tuesday - Mastering Time Management Unlock the Power of OnePlan's Timesh...Tech Tuesday - Mastering Time Management Unlock the Power of OnePlan's Timesh...
Tech Tuesday - Mastering Time Management Unlock the Power of OnePlan's Timesh...OnePlan Solutions
 
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...OnePlan Solutions
 
Machine Learning Software Engineering Patterns and Their Engineering
Machine Learning Software Engineering Patterns and Their EngineeringMachine Learning Software Engineering Patterns and Their Engineering
Machine Learning Software Engineering Patterns and Their EngineeringHironori Washizaki
 
What is Advanced Excel and what are some best practices for designing and cre...
What is Advanced Excel and what are some best practices for designing and cre...What is Advanced Excel and what are some best practices for designing and cre...
What is Advanced Excel and what are some best practices for designing and cre...Technogeeks
 
Powering Real-Time Decisions with Continuous Data Streams
Powering Real-Time Decisions with Continuous Data StreamsPowering Real-Time Decisions with Continuous Data Streams
Powering Real-Time Decisions with Continuous Data StreamsSafe Software
 
Understanding Flamingo - DeepMind's VLM Architecture
Understanding Flamingo - DeepMind's VLM ArchitectureUnderstanding Flamingo - DeepMind's VLM Architecture
Understanding Flamingo - DeepMind's VLM Architecturerahul_net
 
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdfGOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdfAlina Yurenko
 
SensoDat: Simulation-based Sensor Dataset of Self-driving Cars
SensoDat: Simulation-based Sensor Dataset of Self-driving CarsSensoDat: Simulation-based Sensor Dataset of Self-driving Cars
SensoDat: Simulation-based Sensor Dataset of Self-driving CarsChristian Birchler
 
SpotFlow: Tracking Method Calls and States at Runtime
SpotFlow: Tracking Method Calls and States at RuntimeSpotFlow: Tracking Method Calls and States at Runtime
SpotFlow: Tracking Method Calls and States at Runtimeandrehoraa
 
Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...
Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...
Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...Matt Ray
 
Cloud Data Center Network Construction - IEEE
Cloud Data Center Network Construction - IEEECloud Data Center Network Construction - IEEE
Cloud Data Center Network Construction - IEEEVICTOR MAESTRE RAMIREZ
 
Patterns for automating API delivery. API conference
Patterns for automating API delivery. API conferencePatterns for automating API delivery. API conference
Patterns for automating API delivery. API conferencessuser9e7c64
 
Large Language Models for Test Case Evolution and Repair
Large Language Models for Test Case Evolution and RepairLarge Language Models for Test Case Evolution and Repair
Large Language Models for Test Case Evolution and RepairLionel Briand
 
Alfresco TTL#157 - Troubleshooting Made Easy: Deciphering Alfresco mTLS Confi...
Alfresco TTL#157 - Troubleshooting Made Easy: Deciphering Alfresco mTLS Confi...Alfresco TTL#157 - Troubleshooting Made Easy: Deciphering Alfresco mTLS Confi...
Alfresco TTL#157 - Troubleshooting Made Easy: Deciphering Alfresco mTLS Confi...Angel Borroy López
 
Unveiling Design Patterns: A Visual Guide with UML Diagrams
Unveiling Design Patterns: A Visual Guide with UML DiagramsUnveiling Design Patterns: A Visual Guide with UML Diagrams
Unveiling Design Patterns: A Visual Guide with UML DiagramsAhmed Mohamed
 
CRM Contender Series: HubSpot vs. Salesforce
CRM Contender Series: HubSpot vs. SalesforceCRM Contender Series: HubSpot vs. Salesforce
CRM Contender Series: HubSpot vs. SalesforceBrainSell Technologies
 

Dernier (20)

Call Us🔝>༒+91-9711147426⇛Call In girls karol bagh (Delhi)
Call Us🔝>༒+91-9711147426⇛Call In girls karol bagh (Delhi)Call Us🔝>༒+91-9711147426⇛Call In girls karol bagh (Delhi)
Call Us🔝>༒+91-9711147426⇛Call In girls karol bagh (Delhi)
 
Innovate and Collaborate- Harnessing the Power of Open Source Software.pdf
Innovate and Collaborate- Harnessing the Power of Open Source Software.pdfInnovate and Collaborate- Harnessing the Power of Open Source Software.pdf
Innovate and Collaborate- Harnessing the Power of Open Source Software.pdf
 
Sending Calendar Invites on SES and Calendarsnack.pdf
Sending Calendar Invites on SES and Calendarsnack.pdfSending Calendar Invites on SES and Calendarsnack.pdf
Sending Calendar Invites on SES and Calendarsnack.pdf
 
Balasore Best It Company|| Top 10 IT Company || Balasore Software company Odisha
Balasore Best It Company|| Top 10 IT Company || Balasore Software company OdishaBalasore Best It Company|| Top 10 IT Company || Balasore Software company Odisha
Balasore Best It Company|| Top 10 IT Company || Balasore Software company Odisha
 
Tech Tuesday - Mastering Time Management Unlock the Power of OnePlan's Timesh...
Tech Tuesday - Mastering Time Management Unlock the Power of OnePlan's Timesh...Tech Tuesday - Mastering Time Management Unlock the Power of OnePlan's Timesh...
Tech Tuesday - Mastering Time Management Unlock the Power of OnePlan's Timesh...
 
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...
 
Machine Learning Software Engineering Patterns and Their Engineering
Machine Learning Software Engineering Patterns and Their EngineeringMachine Learning Software Engineering Patterns and Their Engineering
Machine Learning Software Engineering Patterns and Their Engineering
 
What is Advanced Excel and what are some best practices for designing and cre...
What is Advanced Excel and what are some best practices for designing and cre...What is Advanced Excel and what are some best practices for designing and cre...
What is Advanced Excel and what are some best practices for designing and cre...
 
Powering Real-Time Decisions with Continuous Data Streams
Powering Real-Time Decisions with Continuous Data StreamsPowering Real-Time Decisions with Continuous Data Streams
Powering Real-Time Decisions with Continuous Data Streams
 
Understanding Flamingo - DeepMind's VLM Architecture
Understanding Flamingo - DeepMind's VLM ArchitectureUnderstanding Flamingo - DeepMind's VLM Architecture
Understanding Flamingo - DeepMind's VLM Architecture
 
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdfGOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
 
SensoDat: Simulation-based Sensor Dataset of Self-driving Cars
SensoDat: Simulation-based Sensor Dataset of Self-driving CarsSensoDat: Simulation-based Sensor Dataset of Self-driving Cars
SensoDat: Simulation-based Sensor Dataset of Self-driving Cars
 
SpotFlow: Tracking Method Calls and States at Runtime
SpotFlow: Tracking Method Calls and States at RuntimeSpotFlow: Tracking Method Calls and States at Runtime
SpotFlow: Tracking Method Calls and States at Runtime
 
Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...
Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...
Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...
 
Cloud Data Center Network Construction - IEEE
Cloud Data Center Network Construction - IEEECloud Data Center Network Construction - IEEE
Cloud Data Center Network Construction - IEEE
 
Patterns for automating API delivery. API conference
Patterns for automating API delivery. API conferencePatterns for automating API delivery. API conference
Patterns for automating API delivery. API conference
 
Large Language Models for Test Case Evolution and Repair
Large Language Models for Test Case Evolution and RepairLarge Language Models for Test Case Evolution and Repair
Large Language Models for Test Case Evolution and Repair
 
Alfresco TTL#157 - Troubleshooting Made Easy: Deciphering Alfresco mTLS Confi...
Alfresco TTL#157 - Troubleshooting Made Easy: Deciphering Alfresco mTLS Confi...Alfresco TTL#157 - Troubleshooting Made Easy: Deciphering Alfresco mTLS Confi...
Alfresco TTL#157 - Troubleshooting Made Easy: Deciphering Alfresco mTLS Confi...
 
Unveiling Design Patterns: A Visual Guide with UML Diagrams
Unveiling Design Patterns: A Visual Guide with UML DiagramsUnveiling Design Patterns: A Visual Guide with UML Diagrams
Unveiling Design Patterns: A Visual Guide with UML Diagrams
 
CRM Contender Series: HubSpot vs. Salesforce
CRM Contender Series: HubSpot vs. SalesforceCRM Contender Series: HubSpot vs. Salesforce
CRM Contender Series: HubSpot vs. Salesforce
 

Mining Functional Patterns

  • 2. Plan today .. • Design Pattern • Algebra • Algebra <=> Functional Patterns • Mining patterns on real world Scala code
  • 3. Code ahead .. Scala code .. .. though the principles apply equally well to any statically typed functional programming language ..
  • 4. Solution to a Problem in Context Design Pattern
  • 5. Solution to a Problem in Context Design Pattern
  • 6. Solution to a Problem in Context Design Pattern
  • 7. Solution to a Problem in Context Design Pattern
  • 8. Solution to a Problem in Context Design Pattern we are given a problemgeneric component (invariant across context of application) context dependent (varies with the context of problem)
  • 9. What is an Algebra ? Algebra is the study of algebraic structures In mathematics, and more specifically in abstract algebra, an algebraic structure is a set (called carrier set or underlying set) with one or more finitary operations defined on it that satisfies a list of axioms - Wikipedia (https://en.wikipedia.org/wiki/Algebraic_structure)
  • 10. Set A ϕ : A × A → A for (a, b) ∈ A ϕ(a, b) a ϕ b given a binary operation for specific a, b or The Algebra of Sets
  • 11. 3 + 2 = 5 7 + 4 = 11 2 + 0 = 2 0 + 6 = 6 8 + 9 = 9 + 8. Binary operation Identity operation Associative operation always produces an integer (closure of operations) One specific instance of the Algebra
  • 12. Set A ϕ : A × A → A given a binary operation (a ϕ b) ϕ c = a ϕ (b ϕ c) associative for (a, b, c) ∈ A Let’s enhance the Algebra ..
  • 13. Set A ϕ : A × A → A given a binary operation (a ϕ b) ϕ c = a ϕ (b ϕ c) associative for (a, b, c) ∈ A The Algebra of Semigroups
  • 14. Set A ϕ : A × A → A given a binary operation (a ϕ b) ϕ c = a ϕ (b ϕ c) associative for (a, b, c) ∈ A a ϕ I = I ϕ a = a for (a, I ) ∈ A identity The Algebra of Monoids
  • 15. Algebra <=> Protocol class Monoid a where mempty :: a mappend :: a -> a -> a
  • 16. Algebra <=> Protocol with Laws class Monoid a where mempty :: a mappend :: a -> a -> a -- Identity laws x <> mempty = x mempty <> x = x -- Associativity (x <> y) <> z = x <> (y <> z)
  • 17. Monoid In Scala trait Semigroup[A] { def combine(x: A, y: A): A } trait Monoid[A] extends Semigroup[A] { def empty: A }
  • 18. Monoid In Scala trait Semigroup[A] { def combine(x: A, y: A): A } trait Monoid[A] extends Semigroup[A] { def empty: A } val intAdditionMonoid: Monoid[Int] = new Monoid[Int] { def empty: Int = 0 def combine(x: Int, y: Int): Int = x + y } • algebra (interface) • reusable • polymorphic • standard library code • instance (implementation) • specific for a datatype val moneyAdditionMonoid: Monoid[Money] = new Monoid[Money] { def empty: Money = ??? def combine(x: Money, y: Money): Money = ??? } • domain specific instance • specific for Money • application library code
  • 19. Monoid In Scala trait Semigroup[A] { def combine(x: A, y: A): A } trait Monoid[A] extends Semigroup[A] { def empty: A } val intAdditionMonoid: Monoid[Int] = new Monoid[Int] { def empty: Int = 0 def combine(x: Int, y: Int): Int = x + y } • algebra (interface) • reusable • polymorphic • standard library code • instance (implementation) • specific for a datatype val moneyAdditionMonoid: Monoid[Money] = new Monoid[Money] { def empty: Money = ??? def combine(x: Money, y: Money): Money = ??? } • domain specific instance • specific for Money • application library code Generic Specific • Specific implementations use the generic protocol/interface • This reusability is enforced by parametricity (no type specific info in the protocol) • Genericity implies reusability
  • 20. Monoid In Scala trait Semigroup[A] { def combine(x: A, y: A): A } trait Monoid[A] extends Semigroup[A] { def empty: A } val intAdditionMonoid: Monoid[Int] = new Monoid[Int] { def empty: Int = 0 def combine(x: Int, y: Int): Int = x + y } • algebra (interface) • reusable • polymorphic • standard library code • instance (implementation) • specific for a datatype val moneyAdditionMonoid: Monoid[Money] = new Monoid[Money] { def empty: Money = ??? def combine(x: Money, y: Money): Money = ??? } • domain specific instance • specific for Money • application library code Pattern Instances generic & reusable context specific
  • 21. Functional Patterns • Generic, reusable algebra • Parametric on types • Clear separation between pattern (algebra) and its instances • Composable through function composition
  • 22. Functional Patterns • Standard vocabulary - people know these terms, know these operations and their types • Rich ecosystem support through standard libraries • Functions defined in only terms of these interfaces / algebra can be reused by application level data types that follow the pattern
  • 23. Functional Patterns - freebies • Given a type that has an instance of a Monoid, if we have a List of such objects, we can combine them for free using the combine function of Monoid.Also note that the behavior of combine is completely polymorphic - depends on the instance of Monoid that you pass in. • Given a typeV that has an instance of a Monoid, Map[K, V] also gets a Monoid. Part of standard library, but as an application developer you get this for free. • .. and there are many such examples ..
  • 24. Functional Patterns - Multiplicative Power Money: Monoid Payment: Monoid Foo: Monoid Bar: Monoid Polymorphic behaviors in the library that expects a Monoid Domain Model Types with Monoid instances def fold[A](fa: F[A]) (implicit A: Monoid[A]): A = // .. def foldMap[A, B](fa: F[A])(f: A => B) (implicit B: Monoid[B]): B = // .. def foldMapM[G[_], A, B](fa: F[A]) (f: A => G[B])(implicit G: Monad[G], B: Monoid[B]): G[B] = // .. (multiply)
  • 25. Domain Model // a sum type for Currency sealed trait Currency case object USD extends Currency case object AUD extends Currency case object JPY extends Currency case object INR extends Currency // a Money can have denominations in multiple // currencies class Money (val items: Map[Currency, BigDecimal]) { def toBaseCurrency: BigDecimal = items.foldLeft(BigDecimal(0)) { case (a, (ccy, amount)) => a + Money.exchangeRateWithUSD.get(ccy).getOrElse(BigDecimal(1)) * amount } def isDebit = toBaseCurrency < 0 }
  • 26. Domain Model object Money { final val zeroMoney = new Money(Map.empty[Currency, BigDecimal]) // smart constructor def apply(amount: BigDecimal, ccy: Currency) = new Money(Map(ccy -> amount)) // concrete implementation: add two Money objects def add(m: Money, n: Money) = new Money( (m.items.toList ++ n.items.toList) .groupBy(_._1) .map { case (k, v) => (k, v.map(_._2).sum) } ) // sample implementation final val exchangeRateWithUSD: Map[Currency, BigDecimal] = Map(AUD -> 0.76, JPY -> 0.009, INR -> 0.016, USD -> 1.0) } concrete implementation of fusing 2 Maps - can we generalize it ?
  • 27. Domain Model import java.time.OffsetDateTime // Account with a specific unique account no case class Account(no: String, name: String, openDate: OffsetDateTime, closeDate: Option[OffsetDateTime] = None) { override def equals(o: Any): Boolean = o match { case Account(`no`, _, _, _) => true case _ => false } override def hashCode() = no. ## } // Payment made for a particular Account case class Payment(account: Account, amount: Money, dateOfPayment: OffsetDateTime)
  • 28. Domain Model import Money._ object Payments { def creditAmount(p: Payment): Money = if (p.amount.isDebit) zeroMoney else p.amount // concrete implementation def valuation(payments: List[Payment]): Money = payments.foldLeft(zeroMoney) { (a, e) => add(a, creditAmount(e)) } // concrete implementation that uses concrete methods of List def maxPayment(payments: List[Payment]): Money = payments.map(creditAmount).maxBy(_.toBaseCurrency) // adjust balances and payments def newBalances(currentBalances: Map[Account, Money], currentPayments: Map[Account, Money]): Map[Account, Money] = { // complicated logic that merges the 2 Maps Map.empty[Account, Money] } } complex implementation of fusing 2 Maps - can we generalize it ? 1. similar contract: Is there any commonality of behaviors that we can extract ? 2. both iterate over the collection and compute an aggregate
  • 29. Domain Model object Money { final val zeroMoney = new Money(Map.empty[Currency, BigDecimal]) // smart constructor def apply(amount: BigDecimal, ccy: Currency) = new Money(Map(ccy -> amount)) // concrete implementation: add two Money objects def add(m: Money, n: Money) = new Money( (m.items.toList ++ n.items.toList) .groupBy(_._1) .map { case (k, v) => (k, v.map(_._2).sum) } ) // sample implementation final val exchangeRateWithUSD: Map[Currency, BigDecimal] = Map(AUD -> 0.76, JPY -> 0.009, INR -> 0.016, USD -> 1.0) } concrete implementation of fusing 2 Maps - can we generalize it ?
  • 30. Domain Model object Money { final val zeroMoney = new Money(Map.empty[Currency, BigDecimal]) // smart constructor def apply(amount: BigDecimal, ccy: Currency) = new Money(Map(ccy -> amount)) // concrete implementation: add two Money objects def add(m: Money, n: Money) = new Money( (m.items.toList ++ n.items.toList) .groupBy(_._1) .map { case (k, v) => (k, v.map(_._2).sum) } ) // sample implementation final val exchangeRateWithUSD: Map[Currency, BigDecimal] = Map(AUD -> 0.76, JPY -> 0.009, INR -> 0.016, USD -> 1.0) } (a) adds 2 Money objects (b) has to be associative identity operation Pattern: Monoid for Money!
  • 31. Domain Model import Money._ object Payments { def creditAmount(p: Payment): Money = if (p.amount.isDebit) zeroMoney else p.amount // concrete implementation def valuation(payments: List[Payment]): Money = payments.foldLeft(zeroMoney) { (a, e) => add(a, creditAmount(e)) } // concrete implementation that uses concrete methods of List def maxPayment(payments: List[Payment]): Money = payments.map(creditAmount).maxBy(_.toBaseCurrency) // adjust balances and payments def newBalances(currentBalances: Map[Account, Money], currentPayments: Map[Account, Money]): Map[Account, Money] = { // complicated logic that merges the 2 Maps Map.empty[Account, Money] } } complex implementation of fusing 2 Maps - can we generalize it ? 1. similar contract: Is there any commonality of behaviors that we can extract ? 2. both iterate over the collection and compute an aggregate
  • 32. Domain Model import Money._ object Payments { def creditAmount(p: Payment): Money = if (p.amount.isDebit) zeroMoney else p.amount // concrete implementation def valuation(payments: List[Payment]): Money = payments.foldLeft(zeroMoney) { (a, e) => add(a, creditAmount(e)) } // concrete implementation that uses concrete methods of List def maxPayment(payments: List[Payment]): Money = payments.map(creditAmount).maxBy(_.toBaseCurrency) // adjust balances and payments def newBalances(currentBalances: Map[Account, Money], currentPayments: Map[Account, Money]): Map[Account, Money] = { // complicated logic that merges the 2 Maps Map.empty[Account, Money] } } 2 different ways to combine a bunch of Money instances (a) combine to add (b) combine to find the max You get a monoid for Map[K, V] if V has a monoid - part of standard library. (a) combine the 2 Maps Pattern: Monoid for Money!
  • 33. Looking Back • Similar problem • Different context • Reuse of the same algebra • Different concrete instances of the algebra
  • 34. import Money._ object Payments { def creditAmount(p: Payment): Money = if (p.amount.isDebit) zeroMoney else p.amount // concrete implementation def valuation(payments: List[Payment]): Money = payments.foldLeft(zeroMoney) { (a, e) => add(a, creditAmount(e)) } // concrete implementation that uses concrete methods of List def maxPayment(payments: List[Payment]): Money = payments.map(creditAmount).maxBy(_.toBaseCurrency) // adjust balances and payments def newBalances(currentBalances: Map[Account, Money], currentPayments: Map[Account, Money]): Map[Account, Money] = { // complicated logic that merges the 2 Maps Map.empty[Account, Money] } } Domain Model • An aggregation that produces a single result • Do we really need a List for the operation that we are doing ? • Use the least powerful abstraction that you need Pattern: Foldable
  • 35. Abstracting over Structure & Operation trait Foldable[F[_]] { def foldleft[A, B](as: F[A], z: B, f: (B, A) => B): B def foldMap[A, B](as: F[A], f: A => B)(implicit m: Monoid[B]): B = foldleft(as, m.zero, (b: B, a: A) => m.combine(b, f(a))) } def mapReduce[F[_], A, B](as: F[A], f: A => B) (implicit ff: Foldable[F], m: Monoid[B]) = ff.foldMap(as, f)
  • 36. Domain Model object Payments extends MoneyInstances with Utils { def creditAmount: Payment => Money = { p => if (p.amount.isDebit) zeroMoney else p.amount } def valuation(payments: List[Payment]): Money = { implicit val m: Monoid[Money] = MoneyAddMonoid mapReduce(payments)(creditAmount) } def maxPayment(payments: List[Payment]): Money = { implicit val m: Monoid[Money] = MoneyOrderMonoid mapReduce(payments)(creditAmount) } def newBalances(currentBalances: Map[Account, Money], currentPayments: Map[Account, Money]): Map[Account, Money] = { implicit val m = MoneyAddMonoid currentBalances |+| currentPayments } } • Completely generic implementation with Money manipulation logic moved to the library code • Reusability FTW
  • 37. Parametricity def mapReduce[F[_], A, B](as: F[A], f: A => B) (implicit ff: Foldable[F], m: Monoid[B]) = ff.foldMap(as, f) • Parametric polymorphism • No dependence on concrete types • Reusable under multiple implementation context • Limited implementation possibilities by definition • Honors the principle of using the least powerful abstraction that works • The most important virtue of good functional patterns
  • 38. Domain Model (Handling Domain Validations) private void validateState() throws ModelCtorException { ModelCtorException ex = new ModelCtorException(); if (FAILS == Check.optional(fId, Check.range(1,50))) { ex.add("Id is optional, 1 ..50 chars."); } if (FAILS == Check.required(fName, Check.range(2,50))) { ex.add("Restaurant Name is required, 2 ..50 chars."); } if (FAILS == Check.optional(fLocation, Check.range(2,50))) { ex.add("Location is optional, 2 ..50 chars."); } Validator[] priceChecks = {Check.range(ZERO, HUNDRED), Check.numDecimalsAlways(2)}; if (FAILS == Check.optional(fPrice, priceChecks)) { ex.add("Price is optional, 0.00 to 100.00."); } if (FAILS == Check.optional(fComment, Check.range(2,50))) { ex.add("Comment is optional, 2 ..50 chars."); } if ( ! ex.isEmpty() ) throw ex; }
  • 39. Domain Model (Managing Configurations) public Handler getHandler(Config config) throws Exception { final String defaultTopic = config.getString("default_topic"); boolean propagate = false; try { propagate = config.getBoolean("propagate"); } catch (ConfigException.Missing ignored) { } if ("null".equals(defaultTopic)) { log.warn("default topic is "null"; messages will be discarded unless tagged with kt:"); } final Properties properties = new Properties(); for (Map.Entry<String, ConfigValue> kv : config.getConfig("producer_config").entrySet()) { properties.put(kv.getKey(), kv.getValue().unwrapped().toString()); } final String clientId = // .. // .. EncryptionConfig encryptionConfig = new EncryptionConfig(); try { Config encryption = config.getConfig("encryption"); encryptionConfig.encryptionKey = encryption.getString("key"); encryptionConfig.encryptionAlgorithm = encryption.getString("algorithm"); encryptionConfig.encryptionTransformation = encryption.getString("transformation"); encryptionConfig.encryptionProvider = encryption.getString("provider"); } catch (ConfigException.Missing ignored) { encryptionConfig = null; } return new KafkaHandler(clientId, propagate, defaultTopic, producer, encryptionConfig); }
  • 40. Antipatterns • Repetition • Imperative, not expression based - hence not composable • Littered with exception handling code (try/catch) - violates referential transparency • Not modular
  • 41. Domain Model type ErrorOr[A] = Either[Exception, A] private def readString(path: String, config: Config): ErrorOr[String] = try { Either.right(config.getString(path)) } catch { case ex: Exception => Either.left(ex) } Step 1: Abstract exceptions with an algebra. We need to handle exceptions, but not throw it upstream case class KafkaSettings( brokers: String, zk: String, fromTopic: String, toTopic: String, errorTopic: String ) Step 2: Use an algebraic data type for configuration information
  • 42. Domain Model type ErrorOr[A] = Either[Exception, A] private def readString(path: String, config: Config): ErrorOr[String] = try { Either.right(config.getString(path)) } catch { case ex: Exception => Either.left(ex) } import com.typesafe.config.Config def fromKafkaConfig(config: Config) = for { b <- readString("dcos.kafka.brokers", config) z <- readString("dcos.kafka.zookeeper", config) f <- readString("dcos.kafka.fromtopic", config) t <- readString("dcos.kafka.totopic", config) e <- readString("dcos.kafka.errortopic", config) } yield KafkaSettings(b, z, f, t, e) • Algebra of Monad for composition of readString • Looks imperative (and hence intuitive) though in reality it’s an expression • Reusing algebra and defining implementation specific context
  • 43. Domain Model import com.typesafe.config.Config def fromKafkaConfig(config: Config): ErrorOr[KafkaSettings] = for { b <- readString("dcos.kafka.brokers", config) z <- readString("dcos.kafka.zookeeper", config) f <- readString("dcos.kafka.fromtopic", config) t <- readString("dcos.kafka.totopic", config) e <- readString("dcos.kafka.errortopic", config) } yield KafkaSettings(b, z, f, t, e) Repetitions ..
  • 44. Algebraic Composition def fromKafkaConfig(config: Config): ErrorOr[KafkaSettings] = for { b <- readString("dcos.kafka.brokers", config) z <- readString("dcos.kafka.zookeeper", config) f <- readString("dcos.kafka.fromtopic", config) t <- readString("dcos.kafka.totopic", config) e <- readString("dcos.kafka.errortopic", config) } yield KafkaSettings(b, z, f, t, e) Either[Exception, KafkaSettings]
  • 45. Algebraic Composition Either[Exception, KafkaSettings]Config => def fromKafkaConfig: Config => ErrorOr[KafkaSettings] = (config: Config) => for { b <- readString("dcos.kafka.brokers", config) z <- readString("dcos.kafka.zookeeper", config) f <- readString("dcos.kafka.fromtopic", config) t <- readString("dcos.kafka.totopic", config) e <- readString("dcos.kafka.errortopic", config) } yield KafkaSettings(b, z, f, t, e) ReaderT[ErrorOr, Config, KafkaSettings] we want a better abstraction for reading stuff in the abstraction needs to compose with Either
  • 46. Algebraic Composition Either[Exception, KafkaSettings]Config => def fromKafkaConfig: Config => ErrorOr[KafkaSettings] = (config: Config) => for { b <- readString("dcos.kafka.brokers", config) z <- readString("dcos.kafka.zookeeper", config) f <- readString("dcos.kafka.fromtopic", config) t <- readString("dcos.kafka.totopic", config) e <- readString("dcos.kafka.errortopic", config) } yield KafkaSettings(b, z, f, t, e) ReaderT[ErrorOr, Config, KafkaSettings] • An algebra abstracting our earlier expression • Does 2 things - the Reader monad wraps a unary function & the T part indicating a monad transformer composes the 2 monads, the Reader and the Either • ReaderT is also a monad
  • 47. Algebraic Composition type ConfigReader[A] = ReaderT[ErrorOr, Config, A] def fromKafkaConfig: ConfigReader[KafkaSettings] = for { b <- readString("dcos.kafka.brokers") z <- readString("dcos.kafka.zookeeper") f <- readString("dcos.kafka.fromtopic") t <- readString("dcos.kafka.totopic") e <- readString("dcos.kafka.errortopic") } yield KafkaSettings(b, z, f, t, e) def readString(path: String): ConfigReader[String] = Kleisli { (config: Config) => try { Either.right(config.getString(path)) } catch { case ex: Exception => Either.left(ex) } }
  • 48. Functional Patterns • Reuse of already existing algebra (Reader, Monad, Either etc.) • Algebraic composition - form larger patterns from smaller ones • Abstraction remains composable • And modular