SlideShare a Scribd company logo
Sum and Product Types
The Fruit Salad & Fruit Snack Example
From F# to Haskell, Scala and Java
@ScottWlaschin
type FruitSalad = {
Apple: AppleVariety
Banana: BananaVariety
Cherries: CherryVariety
}
In F#, new types are built from smaller types in two ways:
• By _AND_ing them together
• By _OR_ing them together
“AND” Types
Let’s start with building types using AND. For example, we might say that to
make fruit salad you need an apple and a banana and some cherries:
“OR” Types
The other way of building new types is by using OR. For example, we might
say that for a fruit snack you need an apple or a banana or some cherries:
@ScottWlaschin
type FruitSnack =
| Apple of AppleVariety
| Banana of BananaVariety
| Cherries of CherryVariety
The varieties of fruit are themselves defined as OR types, which in this case is used
similarly to an enum in other languages.
type AppleVariety =
| GoldenDelicious
| GrannySmith
| Fuji
type BananaVariety =
| Cavendish
| GrosMichel
| Manzano
type CherryVariety =
| Montmorency
| Bing
This can be read as:
• An AppleVariety is either a GoldenDelicious or a GrannySmith or a Fuji, and so on.
@ScottWlaschin
Jargon Alert: “Product Types” and “Sum Types”
The types that are built using AND are called product types.
The types that are built using OR are called sum types or tagged unions or, in F#
terminology, discriminated unions. In this book I will often call them choice types,
because I think that best describes their role in domain modeling.
@philip_schwarz
Let’s translate that F# example into Haskell, Scala and Java.
data FruitSalad = FruitSalad {
apple :: AppleVariety,
banana :: BananaVariety,
cherries :: CherryVariety
}
data FruitSnack
= Apple AppleVariety
| Banana BananaVariety
| Cherries CherryVariety
data AppleVariety
= GoldenDelicious
| GrannySmith
| Fuji
data BananaVariety
= Cavendish
| GrosMichel
| Manzano
data CherryVariety
= Montmorency
| Bing
case class FruitSalad(
apple: AppleVariety,
banana: BananaVariety,
cherries: CherryVariety
)
enum FruitSnack:
case Apple(variety: AppleVariety)
case Banana(variety: BananaVariety)
case Cherries(variety: CherryVariety)
enum AppleVariety:
case GoldenDelicious,
GrannySmith,
Fuji
enum BananaVariety:
case Cavendish,
GrosMichel,
Manzano
enum CherryVariety:
case Montmorency,
Bing
record FruitSalad(
AppleVariety apple,
BananaVariety banana,
CherryVariety cherries
) { }
sealed interface FruitSnack permits Apple, Banana, Cherries { }
record Apple(AppleVariety variety) implements FruitSnack { }
record Banana(BananaVariety variety) implements FruitSnack { }
record Cherries(CherryVariety variety) implements FruitSnack { }
enum AppleVariety {
GOLDEN_DELICIOUS,
GRANNY_SMITH,
FUJI}
enum BananaVariety {
CAVENDISH,
GROS_MICHEL,
MANZANO}
enum CherryVariety {
MONTMORENCY,
BING}
Now, let’s see what the behaviour is when we compare
sample values and when we convert them to strings.
data FruitSalad = FruitSalad {
apple :: AppleVariety,
banana :: BananaVariety,
cherries :: CherryVariety
} deriving (Eq, Show)
data FruitSnack
= Apple AppleVariety
| Banana BananaVariety
| Cherries CherryVariety
deriving (Eq, Show)
data AppleVariety
= GoldenDelicious
| GrannySmith
| Fuji
deriving (Eq, Show)
data BananaVariety
= Cavendish
| GrosMichel
| Manzano
deriving (Eq, Show)
data CherryVariety
= Montmorency
| Bing
deriving (Eq, Show)
main :: IO ()
main =
let
salad = FruitSalad GoldenDelicious Cavendish Montmorency
sameSalad = FruitSalad GoldenDelicious Cavendish Montmorency
differentSalad = FruitSalad GoldenDelicious Manzano Montmorency
snack = Apple GoldenDelicious
sameSnack = Apple GoldenDelicious
differentSnack = Banana Cavendish
in do
assert (show salad == "FruitSalad {apple = GoldenDelicious, banana = Cavendish, cherries = Montmorency}") pure ()
assert (salad == sameSalad) return ()
assert (salad /= differentSalad) return ()
assert (show snack == "Apple GoldenDelicious") return ()
assert (snack == sameSnack) return ()
assert (snack /= differentSnack) return ()
-- Error: Couldn't match expected type ‘FruitSalad’ with actual type ‘FruitSnack’
assert(snack /= salad) return ()
-- Error: Couldn't match expected type ‘FruitSnack’ with actual type ‘AppleVariety’
assert(snack /= GoldenDelicious) return ()
-- Error: Couldn't match expected type ‘FruitSnack’ with actual type ‘AppleVariety’
assert(salad /= GoldenDelicious) return ()
To permit the ‘showing’ of FruitSalad and
FruitSnack values, and also to permit the
comparison of such values, we have added the
following to all types: deriving (Eq, Show).
val salad = FruitSalad(GoldenDelicious, Cavendish, Montmorency);
val sameSalad = FruitSalad(GoldenDelicious, Cavendish, Montmorency);
val differentSalad = FruitSalad(GoldenDelicious, Manzano, Montmorency);
val snack = Apple(GoldenDelicious)
val sameSnack = Apple(GoldenDelicious)
val differentSnack = Banana(Cavendish)
assert(salad.toString == "FruitSalad(GoldenDelicious,Cavendish,Montmorency)")
assert(salad == sameSalad)
assert(salad != differentSalad)
assert(snack.toString == "Apple(GoldenDelicious)")
assert(snack == sameSnack);
assert(snack != differentSnack);
// Compiler error: Values of types FruitSalad and FruitSnack cannot be compared with == or !=
assert(salad != snack)
// Compiler error: Values of types FruitSalad and AppleVariety cannot be compared with == or !=
assert(salad != GoldenDelicious)
// Compiler error: Values of types FruitSnack and AppleVariety cannot be compared with == or !=
assert(snack != GoldenDelicious)
case class FruitSalad(
apple: AppleVariety,
banana: BananaVariety,
cherries: CherryVariety
) derives CanEqual
enum FruitSnack derives CanEqual:
case Apple(variety: AppleVariety)
case Banana(variety: BananaVariety)
case Cherries(variety: CherryVariety)
enum AppleVariety:
case GoldenDelicious,
GrannySmith,
Fuji
enum BananaVariety:
case Cavendish,
GrosMichel,
Manzano
enum CherryVariety:
case Montmorency,
Bing
To prevent meaningless comparisons, e.g.
comparing a salad with a snack, we have
added the following to FruitSalad and
FruitSnack: derives CanEqual.
case class FruitSalad(
apple: AppleVariety,
banana: BananaVariety,
cherries: CherryVariety
) derives CanEqual
enum FruitSnack derives CanEqual:
case Apple(variety: AppleVariety)
case Banana(variety: BananaVariety)
case Cherries(variety: CherryVariety)
enum AppleVariety:
case GoldenDelicious,
GrannySmith,
Fuji
enum BananaVariety:
case Cavendish,
GrosMichel,
Manzano
enum CherryVariety:
case Montmorency,
Bing
products (AND)
degenerate products - single argument
product (AND)
sum (OR)
record FruitSalad(
AppleVariety apple,
BananaVariety banana,
CherryVariety cherries
) { }
sealed interface FruitSnack permits Apple, Banana, Cherries { }
record Apple(AppleVariety variety) implements FruitSnack { }
record Banana(BananaVariety variety) implements FruitSnack { }
record Cherries(CherryVariety variety) implements FruitSnack { }
enum AppleVariety {
GOLDEN_DELICIOUS,
GRANNY_SMITH,
FUJI}
enum BananaVariety {
CAVENDISH,
GROS_MICHEL,
MANZANO}
enum CherryVariety {
MONTMORENCY,
BING}
var salad = new FruitSalad(GOLDEN_DELICIOUS,CAVENDISH, MONTMORENCY);
var sameSalad = new FruitSalad(GOLDEN_DELICIOUS,CAVENDISH, MONTMORENCY);
var differentSalad = new FruitSalad(GOLDEN_DELICIOUS,MANZANO, MONTMORENCY);
var snack = new Apple(GOLDEN_DELICIOUS);
var sameSnack = new Apple(GOLDEN_DELICIOUS);
var differentSnack = new Banana(CAVENDISH);
assert(salad.toString().equals("FruitSalad[apple=GOLDEN_DELICIOUS, banana=CAVENDISH, cherries=MONTMORENCY]"));
assert(salad.equals(sameSalad));
assert(!salad.equals(differentSalad));
assert(snack.toString().equals("Apple[variety=GOLDEN_DELICIOUS]"));
assert(snack.equals(sameSnack));
assert(!snack.equals(differentSnack));
assert(!salad.equals(snack));
assert(!salad.equals(GOLDEN_DELICIOUS));
assert(!snack.equals(GOLDEN_DELICIOUS));
Now, let’s see some pattern matching
@philip_schwarz
pickyCustomerReaction :: FruitSalad -> String
pickyCustomerReaction (FruitSalad Fuji Cavendish Bing) = "That's my favourite combination."
pickyCustomerReaction (FruitSalad GoldenDelicious _ _) = "I can't stand Golden Delicious apples."
pickyCustomerReaction (FruitSalad _ Manzano Bing) = "I both love and hate this."
pickyCustomerReaction (FruitSalad _ Manzano _) = "Manzano is my least favourite banana."
pickyCustomerReaction (FruitSalad _ _ Bing) = "Bing are my favourite cherries."
pickyCustomerReaction _ = "It will do."
data FruitSalad = FruitSalad {
apple :: AppleVariety,
banana :: BananaVariety,
cherries :: CherryVariety
} deriving (Eq, Show)
data FruitSnack
= Apple AppleVariety
| Banana BananaVariety
| Cherries CherryVariety
deriving (Eq, Show)
data AppleVariety
= GoldenDelicious
| GrannySmith
| Fuji
deriving (Eq, Show)
data BananaVariety
= Cavendish
| GrosMichel
| Manzano
deriving (Eq, Show)
data CherryVariety
= Montmorency
| Bing
deriving (Eq, Show)
pickySnackerRemark :: FruitSnack -> String
pickySnackerRemark (Apple Fuji) = "That's my favourite apple."
pickySnackerRemark (Apple GoldenDelicious) = "I can't stand Golden Delicious apples."
pickySnackerRemark (Banana Cavendish) = "That's my favourite banana."
pickySnackerRemark (Banana Manzano) = "Manzano is my least favourite banana."
pickySnackerRemark (Cherries Bing) = "Those are my favourite cherries."
pickySnackerRemark _ = "It will do."
case class FruitSalad(
apple: AppleVariety,
banana: BananaVariety,
cherries: CherryVariety
)
enum FruitSnack:
case Apple(variety: AppleVariety)
case Banana(variety: BananaVariety)
case Cherries(variety: CherryVariety)
enum AppleVariety:
case GoldenDelicious,
GrannySmith,
Fuji
enum BananaVariety:
case Cavendish,
GrosMichel,
Manzano
enum CherryVariety:
case Montmorency,
Bing
val pickyCustomerReaction = salad match
case FruitSalad(Fuji,Cavendish,Bing) => "That's my favourite combination."
case FruitSalad(GoldenDelicious,_,_) => "I can't stand Golden Delicious apples.”
case FruitSalad(_,Manzano,Bing) => "I both love and hate this."
case FruitSalad(_,Manzano,_) => "Manzano is my least favourite banana."
case FruitSalad(_,_,Bing) => "Bing are my favourite cherries."
case _ => "It will do."
val pickySnackerRemark = snack match
case Apple(Fuji) => "That's my favourite apple."
case Apple(GoldenDelicious) => "I can't stand Golden Delicious apples."
case Banana(Cavendish) => "That's my favourite banana."
case Banana(Manzano) => "Manzano is my least favourite banana."
case Cherries(Bing) => "Those are my favourite cherries."
case _ => "It will do."
record FruitSalad(
AppleVariety apple,
BananaVariety banana,
CherryVariety cherries
) { }
sealed interface FruitSnack permits Apple, Banana, Cherries { }
record Apple(AppleVariety variety) implements FruitSnack { }
record Banana(BananaVariety variety) implements FruitSnack { }
record Cherries(CherryVariety variety) implements FruitSnack { }
enum AppleVariety {
GOLDEN_DELICIOUS,
GRANNY_SMITH,
FUJI}
enum BananaVariety {
CAVENDISH,
GROS_MICHEL,
MANZANO}
enum CherryVariety {
MONTMORENCY,
BING}
String pickyCustomerReaction(FruitSalad salad) {
return switch (salad) {
case FruitSalad(var apple, var banana, var cherries)
when apple.equals(FUJI) && banana.equals(CAVENDISH)
&& cherries.equals(BING) ->
"That's my favourite combination.";
case FruitSalad(var apple, var banana, var cherries)
when apple.equals(GOLDEN_DELICIOUS) ->
"I can't stand Golden Delicious apples.";
case FruitSalad(var apple, var banana, var cherries)
when banana.equals(MANZANO) && cherries.equals(BING) ->
"I both love and hate this.";
case FruitSalad(var apple, var banana, var cherries)
when banana.equals(MANZANO) ->
"Manzano is my least favourite banana.";
case FruitSalad(var apple, var banana, var cherries)
when cherries.equals(BING) ->
"Bing are my favourite cherries.";
default -> "It will do.";
};
}
String pickySnackerRemark(FruitSnack snack) {
return switch (snack) {
case Apple(var variety) when variety.equals(FUJI) ->"That's my favourite apple.";
case Apple(var variety) when variety.equals(GOLDEN_DELICIOUS) ->"I can't stand Golden Delicious apples.";
case Banana(var variety) when variety.equals(CAVENDISH) ->"That's my favourite banana.";
case Banana(var variety) when variety.equals(MANZANO) ->"Manzano is my least favourite banana.";
case Cherries(var variety) when variety.equals(BING) ->"Those are my favourite cherries.";
default -> "It will do.";
};
}
In order to run that pattern matching code, I
downloaded the Java 19 early access build.
$ ~/Downloads/jdk-19.jdk/Contents/Home/bin/jshell --enable-preview
| Welcome to JShell -- Version 19-ea
| For an introduction type: /help intro
jshell> record FruitSalad(
...> AppleVariety apple,
...> BananaVariety banana,
...> CherryVariety cherries
...> ) { }
...>
...> sealed interface FruitSnack permits Apple, Banana, Cherries { }
...> record Apple(AppleVariety variety) implements FruitSnack { }
...> record Banana(BananaVariety variety) implements FruitSnack { }
...> record Cherries(CherryVariety variety) implements FruitSnack { }
...>
...> enum AppleVariety {GOLDEN_DELICIOUS, GRANNY_SMITH, FUJI}
...> enum BananaVariety {CAVENDISH, GROS_MICHEL, MANZANO}
...> enum CherryVariety {MONTMORENCY, BING}
| created record FruitSalad, however, it cannot be referenced until class AppleVariety, class BananaVariety, and class CherryVariety are declared
| created interface FruitSnack, however, it cannot be referenced until class Apple, class Banana, and class Cherries are declared
| created record Apple, however, it cannot be referenced until class AppleVariety is declared
| created record Banana, however, it cannot be referenced until class BananaVariety is declared
| created record Cherries, however, it cannot be referenced until class CherryVariety is declared
| created enum AppleVariety
| created enum BananaVariety
| created enum CherryVariety
jshell>
jshell> String pickySnackerRemark(FruitSnack snack) {
...> return switch (snack) {
...> case Apple(var variety) when variety.equals(AppleVariety.FUJI) ->"That's my favourite apple.";
...> case Apple(var variety) when variety.equals(AppleVariety.GOLDEN_DELICIOUS) ->"I can't stand Golden Delicious apples.";
...> case Banana(var variety) when variety.equals(BananaVariety.CAVENDISH) ->"That's my favourite banana.";
...> case Banana(var variety) when variety.equals(BananaVariety.MANZANO) ->"Manzano is my least favourite banana.";
...> case Cherries(var variety) when variety.equals(CherryVariety.BING) ->"Those are my favourite cherries.";
...> default -> "It will do.";
...> };
...> }
| created method pickySnackerRemark(FruitSnack)
jshell> FruitSnack snack = new Banana(BananaVariety.MANZANO);
snack ==> Banana[variety=MANZANO]
jshell> pickySnackerRemark(snack)
$11 ==> "Manzano is my least favourite banana.”
jshell>
jshell> String pickyCustomerReaction(FruitSalad salad) {
...> return switch (salad) {
...> case FruitSalad(var apple, var banana , var cherries)
...> when apple.equals(AppleVariety.FUJI) && banana.equals(BananaVariety.CAVENDISH) && cherries.equals(CherryVariety.BING) ->
...> "That's my favourite combination.";
...> case FruitSalad(var apple, var banana , var cherries)
...> when apple.equals(AppleVariety.GOLDEN_DELICIOUS) ->
...> "I can't stand Golden Delicious apples.";
...> case FruitSalad(var apple, var banana , var cherries)
...> when banana.equals(BananaVariety.MANZANO) ->
...> "Manzano is my least favourite banana.";
...> case FruitSalad(var apple, var banana , var cherries)
...> when cherries.equals(CherryVariety.BING) ->
...> "Bing are my favourite cherries.";
...> case FruitSalad(var apple, var banana , var cherries)
...> when banana.equals(BananaVariety.MANZANO) && cherries.equals(CherryVariety.BING) ->
...> "I both love and hate this.";
...> default -> "It will do.";
...> };
...> }
| created method pickyCustomerReaction(FruitSalad)
jshell> var salad = new FruitSalad(AppleVariety.GOLDEN_DELICIOUS,BananaVariety.CAVENDISH, CherryVariety.MONTMORENCY);
salad ==> FruitSalad[apple=GOLDEN_DELICIOUS, banana=CAVENDISH, cherries=MONTMORENCY]
jshell> pickyCustomerReaction(salad);
$14 ==> "I can't stand Golden Delicious apples."
jshell>
I had a go at applying those suggestions.
The first one was fine.
When I tried the second one, I ran into some issues.
If I find out more from Brian Goetz, or I manage to resolve
the issue, then I’ll publish a new version of this deck.
That’s all. I hope you found it useful.
@philip_schwarz
Ad

More Related Content

What's hot (20)

The Expression Problem - Part 1
The Expression Problem - Part 1The Expression Problem - Part 1
The Expression Problem - Part 1
Philip Schwarz
 
Functional Programming 101 with Scala and ZIO @FunctionalWorld
Functional Programming 101 with Scala and ZIO @FunctionalWorldFunctional Programming 101 with Scala and ZIO @FunctionalWorld
Functional Programming 101 with Scala and ZIO @FunctionalWorld
Jorge Vásquez
 
The Functional Programming Triad of Map, Filter and Fold
The Functional Programming Triad of Map, Filter and FoldThe Functional Programming Triad of Map, Filter and Fold
The Functional Programming Triad of Map, Filter and Fold
Philip Schwarz
 
Monoids - Part 1 - with examples using Scalaz and Cats
Monoids - Part 1 - with examples using Scalaz and CatsMonoids - Part 1 - with examples using Scalaz and Cats
Monoids - Part 1 - with examples using Scalaz and Cats
Philip Schwarz
 
Kleisli Composition
Kleisli CompositionKleisli Composition
Kleisli Composition
Philip Schwarz
 
Py.test
Py.testPy.test
Py.test
soasme
 
Scala 3 by Example - Algebraic Data Types for Domain Driven Design - Part 1
Scala 3 by Example - Algebraic Data Types for Domain Driven Design - Part 1Scala 3 by Example - Algebraic Data Types for Domain Driven Design - Part 1
Scala 3 by Example - Algebraic Data Types for Domain Driven Design - Part 1
Philip Schwarz
 
Designing Structured Streaming Pipelines—How to Architect Things Right
Designing Structured Streaming Pipelines—How to Architect Things RightDesigning Structured Streaming Pipelines—How to Architect Things Right
Designing Structured Streaming Pipelines—How to Architect Things Right
Databricks
 
Clean Code
Clean CodeClean Code
Clean Code
swaraj Patil
 
Solving PostgreSQL wicked problems
Solving PostgreSQL wicked problemsSolving PostgreSQL wicked problems
Solving PostgreSQL wicked problems
Alexander Korotkov
 
Clean Lambdas & Streams in Java8
Clean Lambdas & Streams in Java8Clean Lambdas & Streams in Java8
Clean Lambdas & Streams in Java8
Victor Rentea
 
PostgreSQL Deep Internal
PostgreSQL Deep InternalPostgreSQL Deep Internal
PostgreSQL Deep Internal
EXEM
 
Real Life Clean Architecture
Real Life Clean ArchitectureReal Life Clean Architecture
Real Life Clean Architecture
Mattia Battiston
 
AWS 환경에서 MySQL BMT
AWS 환경에서 MySQL BMTAWS 환경에서 MySQL BMT
AWS 환경에서 MySQL BMT
I Goo Lee
 
Bloat and Fragmentation in PostgreSQL
Bloat and Fragmentation in PostgreSQLBloat and Fragmentation in PostgreSQL
Bloat and Fragmentation in PostgreSQL
Masahiko Sawada
 
Http4s, Doobie and Circe: The Functional Web Stack
Http4s, Doobie and Circe: The Functional Web StackHttp4s, Doobie and Circe: The Functional Web Stack
Http4s, Doobie and Circe: The Functional Web Stack
GaryCoady
 
Monad as functor with pair of natural transformations
Monad as functor with pair of natural transformationsMonad as functor with pair of natural transformations
Monad as functor with pair of natural transformations
Philip Schwarz
 
SOLID, DRY, SLAP design principles
SOLID, DRY, SLAP design principlesSOLID, DRY, SLAP design principles
SOLID, DRY, SLAP design principles
Sergey Karpushin
 
Analyzing Petabyte Scale Financial Data with Apache Pinot and Apache Kafka | ...
Analyzing Petabyte Scale Financial Data with Apache Pinot and Apache Kafka | ...Analyzing Petabyte Scale Financial Data with Apache Pinot and Apache Kafka | ...
Analyzing Petabyte Scale Financial Data with Apache Pinot and Apache Kafka | ...
HostedbyConfluent
 
The Expression Problem - Part 1
The Expression Problem - Part 1The Expression Problem - Part 1
The Expression Problem - Part 1
Philip Schwarz
 
Functional Programming 101 with Scala and ZIO @FunctionalWorld
Functional Programming 101 with Scala and ZIO @FunctionalWorldFunctional Programming 101 with Scala and ZIO @FunctionalWorld
Functional Programming 101 with Scala and ZIO @FunctionalWorld
Jorge Vásquez
 
The Functional Programming Triad of Map, Filter and Fold
The Functional Programming Triad of Map, Filter and FoldThe Functional Programming Triad of Map, Filter and Fold
The Functional Programming Triad of Map, Filter and Fold
Philip Schwarz
 
Monoids - Part 1 - with examples using Scalaz and Cats
Monoids - Part 1 - with examples using Scalaz and CatsMonoids - Part 1 - with examples using Scalaz and Cats
Monoids - Part 1 - with examples using Scalaz and Cats
Philip Schwarz
 
Py.test
Py.testPy.test
Py.test
soasme
 
Scala 3 by Example - Algebraic Data Types for Domain Driven Design - Part 1
Scala 3 by Example - Algebraic Data Types for Domain Driven Design - Part 1Scala 3 by Example - Algebraic Data Types for Domain Driven Design - Part 1
Scala 3 by Example - Algebraic Data Types for Domain Driven Design - Part 1
Philip Schwarz
 
Designing Structured Streaming Pipelines—How to Architect Things Right
Designing Structured Streaming Pipelines—How to Architect Things RightDesigning Structured Streaming Pipelines—How to Architect Things Right
Designing Structured Streaming Pipelines—How to Architect Things Right
Databricks
 
Solving PostgreSQL wicked problems
Solving PostgreSQL wicked problemsSolving PostgreSQL wicked problems
Solving PostgreSQL wicked problems
Alexander Korotkov
 
Clean Lambdas & Streams in Java8
Clean Lambdas & Streams in Java8Clean Lambdas & Streams in Java8
Clean Lambdas & Streams in Java8
Victor Rentea
 
PostgreSQL Deep Internal
PostgreSQL Deep InternalPostgreSQL Deep Internal
PostgreSQL Deep Internal
EXEM
 
Real Life Clean Architecture
Real Life Clean ArchitectureReal Life Clean Architecture
Real Life Clean Architecture
Mattia Battiston
 
AWS 환경에서 MySQL BMT
AWS 환경에서 MySQL BMTAWS 환경에서 MySQL BMT
AWS 환경에서 MySQL BMT
I Goo Lee
 
Bloat and Fragmentation in PostgreSQL
Bloat and Fragmentation in PostgreSQLBloat and Fragmentation in PostgreSQL
Bloat and Fragmentation in PostgreSQL
Masahiko Sawada
 
Http4s, Doobie and Circe: The Functional Web Stack
Http4s, Doobie and Circe: The Functional Web StackHttp4s, Doobie and Circe: The Functional Web Stack
Http4s, Doobie and Circe: The Functional Web Stack
GaryCoady
 
Monad as functor with pair of natural transformations
Monad as functor with pair of natural transformationsMonad as functor with pair of natural transformations
Monad as functor with pair of natural transformations
Philip Schwarz
 
SOLID, DRY, SLAP design principles
SOLID, DRY, SLAP design principlesSOLID, DRY, SLAP design principles
SOLID, DRY, SLAP design principles
Sergey Karpushin
 
Analyzing Petabyte Scale Financial Data with Apache Pinot and Apache Kafka | ...
Analyzing Petabyte Scale Financial Data with Apache Pinot and Apache Kafka | ...Analyzing Petabyte Scale Financial Data with Apache Pinot and Apache Kafka | ...
Analyzing Petabyte Scale Financial Data with Apache Pinot and Apache Kafka | ...
HostedbyConfluent
 

More from Philip Schwarz (20)

The Nature of Complexity in John Ousterhout’s Philosophy of Software Design
The Nature of Complexity in John Ousterhout’sPhilosophy of Software DesignThe Nature of Complexity in John Ousterhout’sPhilosophy of Software Design
The Nature of Complexity in John Ousterhout’s Philosophy of Software Design
Philip Schwarz
 
Drawing Heighway’s Dragon - Part 3 - Simplification Through Separation of Con...
Drawing Heighway’s Dragon - Part 3 - Simplification Through Separation of Con...Drawing Heighway’s Dragon - Part 3 - Simplification Through Separation of Con...
Drawing Heighway’s Dragon - Part 3 - Simplification Through Separation of Con...
Philip Schwarz
 
The Open-Closed Principle - Part 2 - The Contemporary Version - An Introduction
The Open-Closed Principle - Part 2 - The Contemporary Version - An IntroductionThe Open-Closed Principle - Part 2 - The Contemporary Version - An Introduction
The Open-Closed Principle - Part 2 - The Contemporary Version - An Introduction
Philip Schwarz
 
The Open-Closed Principle - Part 1 - The Original Version
The Open-Closed Principle - Part 1 - The Original VersionThe Open-Closed Principle - Part 1 - The Original Version
The Open-Closed Principle - Part 1 - The Original Version
Philip Schwarz
 
Drawing Heighway’s Dragon - Part II - Recursive Function Simplification - Fro...
Drawing Heighway’s Dragon - Part II - Recursive Function Simplification - Fro...Drawing Heighway’s Dragon - Part II - Recursive Function Simplification - Fro...
Drawing Heighway’s Dragon - Part II - Recursive Function Simplification - Fro...
Philip Schwarz
 
Drawing Heighway’s Dragon - Recursive Function Rewrite - From Imperative Styl...
Drawing Heighway’s Dragon - Recursive Function Rewrite - From Imperative Styl...Drawing Heighway’s Dragon - Recursive Function Rewrite - From Imperative Styl...
Drawing Heighway’s Dragon - Recursive Function Rewrite - From Imperative Styl...
Philip Schwarz
 
Fibonacci Function Gallery - Part 2 - One in a series
Fibonacci Function Gallery - Part 2 - One in a seriesFibonacci Function Gallery - Part 2 - One in a series
Fibonacci Function Gallery - Part 2 - One in a series
Philip Schwarz
 
Fibonacci Function Gallery - Part 1 (of a series) - with minor corrections
Fibonacci Function Gallery - Part 1 (of a series) - with minor correctionsFibonacci Function Gallery - Part 1 (of a series) - with minor corrections
Fibonacci Function Gallery - Part 1 (of a series) - with minor corrections
Philip Schwarz
 
Fibonacci Function Gallery - Part 1 (of a series)
Fibonacci Function Gallery - Part 1 (of a series)Fibonacci Function Gallery - Part 1 (of a series)
Fibonacci Function Gallery - Part 1 (of a series)
Philip Schwarz
 
The Debt Metaphor - Ward Cunningham in his 2009 YouTube video
The Debt Metaphor -Ward Cunningham in his 2009 YouTube videoThe Debt Metaphor -Ward Cunningham in his 2009 YouTube video
The Debt Metaphor - Ward Cunningham in his 2009 YouTube video
Philip Schwarz
 
Folding Cheat Sheet Series Titles (so far)
Folding Cheat Sheet Series Titles (so far)Folding Cheat Sheet Series Titles (so far)
Folding Cheat Sheet Series Titles (so far)
Philip Schwarz
 
From Subtype Polymorphism To Typeclass-based Ad hoc Polymorphism - An Example
From Subtype Polymorphism To Typeclass-based Ad hoc Polymorphism - An ExampleFrom Subtype Polymorphism To Typeclass-based Ad hoc Polymorphism - An Example
From Subtype Polymorphism To Typeclass-based Ad hoc Polymorphism - An Example
Philip Schwarz
 
Folding Cheat Sheet #8 - eighth in a series
Folding Cheat Sheet #8 - eighth in a seriesFolding Cheat Sheet #8 - eighth in a series
Folding Cheat Sheet #8 - eighth in a series
Philip Schwarz
 
Function Applicative for Great Good of Leap Year Function
Function Applicative for Great Good of Leap Year FunctionFunction Applicative for Great Good of Leap Year Function
Function Applicative for Great Good of Leap Year Function
Philip Schwarz
 
Folding Cheat Sheet #7 - seventh in a series
Folding Cheat Sheet #7 - seventh in a seriesFolding Cheat Sheet #7 - seventh in a series
Folding Cheat Sheet #7 - seventh in a series
Philip Schwarz
 
Folding Cheat Sheet #6 - sixth in a series
Folding Cheat Sheet #6 - sixth in a seriesFolding Cheat Sheet #6 - sixth in a series
Folding Cheat Sheet #6 - sixth in a series
Philip Schwarz
 
Folding Cheat Sheet #5 - fifth in a series
Folding Cheat Sheet #5 - fifth in a seriesFolding Cheat Sheet #5 - fifth in a series
Folding Cheat Sheet #5 - fifth in a series
Philip Schwarz
 
Hand Rolled Applicative User Validation Code Kata
Hand Rolled Applicative User ValidationCode KataHand Rolled Applicative User ValidationCode Kata
Hand Rolled Applicative User Validation Code Kata
Philip Schwarz
 
A Sighting of filterA in Typelevel Rite of Passage
A Sighting of filterA in Typelevel Rite of PassageA Sighting of filterA in Typelevel Rite of Passage
A Sighting of filterA in Typelevel Rite of Passage
Philip Schwarz
 
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
Direct Style Effect Systems -The Print[A] Example- A Comprehension AidDirect Style Effect Systems -The Print[A] Example- A Comprehension Aid
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
Philip Schwarz
 
The Nature of Complexity in John Ousterhout’s Philosophy of Software Design
The Nature of Complexity in John Ousterhout’sPhilosophy of Software DesignThe Nature of Complexity in John Ousterhout’sPhilosophy of Software Design
The Nature of Complexity in John Ousterhout’s Philosophy of Software Design
Philip Schwarz
 
Drawing Heighway’s Dragon - Part 3 - Simplification Through Separation of Con...
Drawing Heighway’s Dragon - Part 3 - Simplification Through Separation of Con...Drawing Heighway’s Dragon - Part 3 - Simplification Through Separation of Con...
Drawing Heighway’s Dragon - Part 3 - Simplification Through Separation of Con...
Philip Schwarz
 
The Open-Closed Principle - Part 2 - The Contemporary Version - An Introduction
The Open-Closed Principle - Part 2 - The Contemporary Version - An IntroductionThe Open-Closed Principle - Part 2 - The Contemporary Version - An Introduction
The Open-Closed Principle - Part 2 - The Contemporary Version - An Introduction
Philip Schwarz
 
The Open-Closed Principle - Part 1 - The Original Version
The Open-Closed Principle - Part 1 - The Original VersionThe Open-Closed Principle - Part 1 - The Original Version
The Open-Closed Principle - Part 1 - The Original Version
Philip Schwarz
 
Drawing Heighway’s Dragon - Part II - Recursive Function Simplification - Fro...
Drawing Heighway’s Dragon - Part II - Recursive Function Simplification - Fro...Drawing Heighway’s Dragon - Part II - Recursive Function Simplification - Fro...
Drawing Heighway’s Dragon - Part II - Recursive Function Simplification - Fro...
Philip Schwarz
 
Drawing Heighway’s Dragon - Recursive Function Rewrite - From Imperative Styl...
Drawing Heighway’s Dragon - Recursive Function Rewrite - From Imperative Styl...Drawing Heighway’s Dragon - Recursive Function Rewrite - From Imperative Styl...
Drawing Heighway’s Dragon - Recursive Function Rewrite - From Imperative Styl...
Philip Schwarz
 
Fibonacci Function Gallery - Part 2 - One in a series
Fibonacci Function Gallery - Part 2 - One in a seriesFibonacci Function Gallery - Part 2 - One in a series
Fibonacci Function Gallery - Part 2 - One in a series
Philip Schwarz
 
Fibonacci Function Gallery - Part 1 (of a series) - with minor corrections
Fibonacci Function Gallery - Part 1 (of a series) - with minor correctionsFibonacci Function Gallery - Part 1 (of a series) - with minor corrections
Fibonacci Function Gallery - Part 1 (of a series) - with minor corrections
Philip Schwarz
 
Fibonacci Function Gallery - Part 1 (of a series)
Fibonacci Function Gallery - Part 1 (of a series)Fibonacci Function Gallery - Part 1 (of a series)
Fibonacci Function Gallery - Part 1 (of a series)
Philip Schwarz
 
The Debt Metaphor - Ward Cunningham in his 2009 YouTube video
The Debt Metaphor -Ward Cunningham in his 2009 YouTube videoThe Debt Metaphor -Ward Cunningham in his 2009 YouTube video
The Debt Metaphor - Ward Cunningham in his 2009 YouTube video
Philip Schwarz
 
Folding Cheat Sheet Series Titles (so far)
Folding Cheat Sheet Series Titles (so far)Folding Cheat Sheet Series Titles (so far)
Folding Cheat Sheet Series Titles (so far)
Philip Schwarz
 
From Subtype Polymorphism To Typeclass-based Ad hoc Polymorphism - An Example
From Subtype Polymorphism To Typeclass-based Ad hoc Polymorphism - An ExampleFrom Subtype Polymorphism To Typeclass-based Ad hoc Polymorphism - An Example
From Subtype Polymorphism To Typeclass-based Ad hoc Polymorphism - An Example
Philip Schwarz
 
Folding Cheat Sheet #8 - eighth in a series
Folding Cheat Sheet #8 - eighth in a seriesFolding Cheat Sheet #8 - eighth in a series
Folding Cheat Sheet #8 - eighth in a series
Philip Schwarz
 
Function Applicative for Great Good of Leap Year Function
Function Applicative for Great Good of Leap Year FunctionFunction Applicative for Great Good of Leap Year Function
Function Applicative for Great Good of Leap Year Function
Philip Schwarz
 
Folding Cheat Sheet #7 - seventh in a series
Folding Cheat Sheet #7 - seventh in a seriesFolding Cheat Sheet #7 - seventh in a series
Folding Cheat Sheet #7 - seventh in a series
Philip Schwarz
 
Folding Cheat Sheet #6 - sixth in a series
Folding Cheat Sheet #6 - sixth in a seriesFolding Cheat Sheet #6 - sixth in a series
Folding Cheat Sheet #6 - sixth in a series
Philip Schwarz
 
Folding Cheat Sheet #5 - fifth in a series
Folding Cheat Sheet #5 - fifth in a seriesFolding Cheat Sheet #5 - fifth in a series
Folding Cheat Sheet #5 - fifth in a series
Philip Schwarz
 
Hand Rolled Applicative User Validation Code Kata
Hand Rolled Applicative User ValidationCode KataHand Rolled Applicative User ValidationCode Kata
Hand Rolled Applicative User Validation Code Kata
Philip Schwarz
 
A Sighting of filterA in Typelevel Rite of Passage
A Sighting of filterA in Typelevel Rite of PassageA Sighting of filterA in Typelevel Rite of Passage
A Sighting of filterA in Typelevel Rite of Passage
Philip Schwarz
 
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
Direct Style Effect Systems -The Print[A] Example- A Comprehension AidDirect Style Effect Systems -The Print[A] Example- A Comprehension Aid
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
Philip Schwarz
 
Ad

Recently uploaded (20)

wAIred_LearnWithOutAI_JCON_14052025.pptx
wAIred_LearnWithOutAI_JCON_14052025.pptxwAIred_LearnWithOutAI_JCON_14052025.pptx
wAIred_LearnWithOutAI_JCON_14052025.pptx
SimonedeGijt
 
How I solved production issues with OpenTelemetry
How I solved production issues with OpenTelemetryHow I solved production issues with OpenTelemetry
How I solved production issues with OpenTelemetry
Cees Bos
 
!%& IDM Crack with Internet Download Manager 6.42 Build 32 >
!%& IDM Crack with Internet Download Manager 6.42 Build 32 >!%& IDM Crack with Internet Download Manager 6.42 Build 32 >
!%& IDM Crack with Internet Download Manager 6.42 Build 32 >
Ranking Google
 
Mobile Application Developer Dubai | Custom App Solutions by Ajath
Mobile Application Developer Dubai | Custom App Solutions by AjathMobile Application Developer Dubai | Custom App Solutions by Ajath
Mobile Application Developer Dubai | Custom App Solutions by Ajath
Ajath Infotech Technologies LLC
 
Serato DJ Pro Crack Latest Version 2025??
Serato DJ Pro Crack Latest Version 2025??Serato DJ Pro Crack Latest Version 2025??
Serato DJ Pro Crack Latest Version 2025??
Web Designer
 
Reinventing Microservices Efficiency and Innovation with Single-Runtime
Reinventing Microservices Efficiency and Innovation with Single-RuntimeReinventing Microservices Efficiency and Innovation with Single-Runtime
Reinventing Microservices Efficiency and Innovation with Single-Runtime
Natan Silnitsky
 
Unit Two - Java Architecture and OOPS
Unit Two  -   Java Architecture and OOPSUnit Two  -   Java Architecture and OOPS
Unit Two - Java Architecture and OOPS
Nabin Dhakal
 
Programs as Values - Write code and don't get lost
Programs as Values - Write code and don't get lostPrograms as Values - Write code and don't get lost
Programs as Values - Write code and don't get lost
Pierangelo Cecchetto
 
Orion Context Broker introduction 20250509
Orion Context Broker introduction 20250509Orion Context Broker introduction 20250509
Orion Context Broker introduction 20250509
Fermin Galan
 
Download MathType Crack Version 2025???
Download MathType Crack  Version 2025???Download MathType Crack  Version 2025???
Download MathType Crack Version 2025???
Google
 
Surviving a Downturn Making Smarter Portfolio Decisions with OnePlan - Webina...
Surviving a Downturn Making Smarter Portfolio Decisions with OnePlan - Webina...Surviving a Downturn Making Smarter Portfolio Decisions with OnePlan - Webina...
Surviving a Downturn Making Smarter Portfolio Decisions with OnePlan - Webina...
OnePlan Solutions
 
sequencediagrams.pptx software Engineering
sequencediagrams.pptx software Engineeringsequencediagrams.pptx software Engineering
sequencediagrams.pptx software Engineering
aashrithakondapalli8
 
A Comprehensive Guide to CRM Software Benefits for Every Business Stage
A Comprehensive Guide to CRM Software Benefits for Every Business StageA Comprehensive Guide to CRM Software Benefits for Every Business Stage
A Comprehensive Guide to CRM Software Benefits for Every Business Stage
SynapseIndia
 
Deploying & Testing Agentforce - End-to-end with Copado - Ewenb Clark
Deploying & Testing Agentforce - End-to-end with Copado - Ewenb ClarkDeploying & Testing Agentforce - End-to-end with Copado - Ewenb Clark
Deploying & Testing Agentforce - End-to-end with Copado - Ewenb Clark
Peter Caitens
 
Autodesk Inventor Crack (2025) Latest
Autodesk Inventor    Crack (2025) LatestAutodesk Inventor    Crack (2025) Latest
Autodesk Inventor Crack (2025) Latest
Google
 
Troubleshooting JVM Outages – 3 Fortune 500 case studies
Troubleshooting JVM Outages – 3 Fortune 500 case studiesTroubleshooting JVM Outages – 3 Fortune 500 case studies
Troubleshooting JVM Outages – 3 Fortune 500 case studies
Tier1 app
 
The-Future-is-Hybrid-Exploring-Azure’s-Role-in-Multi-Cloud-Strategies.pptx
The-Future-is-Hybrid-Exploring-Azure’s-Role-in-Multi-Cloud-Strategies.pptxThe-Future-is-Hybrid-Exploring-Azure’s-Role-in-Multi-Cloud-Strategies.pptx
The-Future-is-Hybrid-Exploring-Azure’s-Role-in-Multi-Cloud-Strategies.pptx
james brownuae
 
Artificial hand using embedded system.pptx
Artificial hand using embedded system.pptxArtificial hand using embedded system.pptx
Artificial hand using embedded system.pptx
bhoomigowda12345
 
Mastering Selenium WebDriver: A Comprehensive Tutorial with Real-World Examples
Mastering Selenium WebDriver: A Comprehensive Tutorial with Real-World ExamplesMastering Selenium WebDriver: A Comprehensive Tutorial with Real-World Examples
Mastering Selenium WebDriver: A Comprehensive Tutorial with Real-World Examples
jamescantor38
 
Top Magento Hyvä Theme Features That Make It Ideal for E-commerce.pdf
Top Magento Hyvä Theme Features That Make It Ideal for E-commerce.pdfTop Magento Hyvä Theme Features That Make It Ideal for E-commerce.pdf
Top Magento Hyvä Theme Features That Make It Ideal for E-commerce.pdf
evrigsolution
 
wAIred_LearnWithOutAI_JCON_14052025.pptx
wAIred_LearnWithOutAI_JCON_14052025.pptxwAIred_LearnWithOutAI_JCON_14052025.pptx
wAIred_LearnWithOutAI_JCON_14052025.pptx
SimonedeGijt
 
How I solved production issues with OpenTelemetry
How I solved production issues with OpenTelemetryHow I solved production issues with OpenTelemetry
How I solved production issues with OpenTelemetry
Cees Bos
 
!%& IDM Crack with Internet Download Manager 6.42 Build 32 >
!%& IDM Crack with Internet Download Manager 6.42 Build 32 >!%& IDM Crack with Internet Download Manager 6.42 Build 32 >
!%& IDM Crack with Internet Download Manager 6.42 Build 32 >
Ranking Google
 
Mobile Application Developer Dubai | Custom App Solutions by Ajath
Mobile Application Developer Dubai | Custom App Solutions by AjathMobile Application Developer Dubai | Custom App Solutions by Ajath
Mobile Application Developer Dubai | Custom App Solutions by Ajath
Ajath Infotech Technologies LLC
 
Serato DJ Pro Crack Latest Version 2025??
Serato DJ Pro Crack Latest Version 2025??Serato DJ Pro Crack Latest Version 2025??
Serato DJ Pro Crack Latest Version 2025??
Web Designer
 
Reinventing Microservices Efficiency and Innovation with Single-Runtime
Reinventing Microservices Efficiency and Innovation with Single-RuntimeReinventing Microservices Efficiency and Innovation with Single-Runtime
Reinventing Microservices Efficiency and Innovation with Single-Runtime
Natan Silnitsky
 
Unit Two - Java Architecture and OOPS
Unit Two  -   Java Architecture and OOPSUnit Two  -   Java Architecture and OOPS
Unit Two - Java Architecture and OOPS
Nabin Dhakal
 
Programs as Values - Write code and don't get lost
Programs as Values - Write code and don't get lostPrograms as Values - Write code and don't get lost
Programs as Values - Write code and don't get lost
Pierangelo Cecchetto
 
Orion Context Broker introduction 20250509
Orion Context Broker introduction 20250509Orion Context Broker introduction 20250509
Orion Context Broker introduction 20250509
Fermin Galan
 
Download MathType Crack Version 2025???
Download MathType Crack  Version 2025???Download MathType Crack  Version 2025???
Download MathType Crack Version 2025???
Google
 
Surviving a Downturn Making Smarter Portfolio Decisions with OnePlan - Webina...
Surviving a Downturn Making Smarter Portfolio Decisions with OnePlan - Webina...Surviving a Downturn Making Smarter Portfolio Decisions with OnePlan - Webina...
Surviving a Downturn Making Smarter Portfolio Decisions with OnePlan - Webina...
OnePlan Solutions
 
sequencediagrams.pptx software Engineering
sequencediagrams.pptx software Engineeringsequencediagrams.pptx software Engineering
sequencediagrams.pptx software Engineering
aashrithakondapalli8
 
A Comprehensive Guide to CRM Software Benefits for Every Business Stage
A Comprehensive Guide to CRM Software Benefits for Every Business StageA Comprehensive Guide to CRM Software Benefits for Every Business Stage
A Comprehensive Guide to CRM Software Benefits for Every Business Stage
SynapseIndia
 
Deploying & Testing Agentforce - End-to-end with Copado - Ewenb Clark
Deploying & Testing Agentforce - End-to-end with Copado - Ewenb ClarkDeploying & Testing Agentforce - End-to-end with Copado - Ewenb Clark
Deploying & Testing Agentforce - End-to-end with Copado - Ewenb Clark
Peter Caitens
 
Autodesk Inventor Crack (2025) Latest
Autodesk Inventor    Crack (2025) LatestAutodesk Inventor    Crack (2025) Latest
Autodesk Inventor Crack (2025) Latest
Google
 
Troubleshooting JVM Outages – 3 Fortune 500 case studies
Troubleshooting JVM Outages – 3 Fortune 500 case studiesTroubleshooting JVM Outages – 3 Fortune 500 case studies
Troubleshooting JVM Outages – 3 Fortune 500 case studies
Tier1 app
 
The-Future-is-Hybrid-Exploring-Azure’s-Role-in-Multi-Cloud-Strategies.pptx
The-Future-is-Hybrid-Exploring-Azure’s-Role-in-Multi-Cloud-Strategies.pptxThe-Future-is-Hybrid-Exploring-Azure’s-Role-in-Multi-Cloud-Strategies.pptx
The-Future-is-Hybrid-Exploring-Azure’s-Role-in-Multi-Cloud-Strategies.pptx
james brownuae
 
Artificial hand using embedded system.pptx
Artificial hand using embedded system.pptxArtificial hand using embedded system.pptx
Artificial hand using embedded system.pptx
bhoomigowda12345
 
Mastering Selenium WebDriver: A Comprehensive Tutorial with Real-World Examples
Mastering Selenium WebDriver: A Comprehensive Tutorial with Real-World ExamplesMastering Selenium WebDriver: A Comprehensive Tutorial with Real-World Examples
Mastering Selenium WebDriver: A Comprehensive Tutorial with Real-World Examples
jamescantor38
 
Top Magento Hyvä Theme Features That Make It Ideal for E-commerce.pdf
Top Magento Hyvä Theme Features That Make It Ideal for E-commerce.pdfTop Magento Hyvä Theme Features That Make It Ideal for E-commerce.pdf
Top Magento Hyvä Theme Features That Make It Ideal for E-commerce.pdf
evrigsolution
 
Ad

Sum and Product Types - The Fruit Salad & Fruit Snack Example - From F# to Haskell, Scala and Java

  • 1. Sum and Product Types The Fruit Salad & Fruit Snack Example From F# to Haskell, Scala and Java @ScottWlaschin
  • 2. type FruitSalad = { Apple: AppleVariety Banana: BananaVariety Cherries: CherryVariety } In F#, new types are built from smaller types in two ways: • By _AND_ing them together • By _OR_ing them together “AND” Types Let’s start with building types using AND. For example, we might say that to make fruit salad you need an apple and a banana and some cherries: “OR” Types The other way of building new types is by using OR. For example, we might say that for a fruit snack you need an apple or a banana or some cherries: @ScottWlaschin type FruitSnack = | Apple of AppleVariety | Banana of BananaVariety | Cherries of CherryVariety
  • 3. The varieties of fruit are themselves defined as OR types, which in this case is used similarly to an enum in other languages. type AppleVariety = | GoldenDelicious | GrannySmith | Fuji type BananaVariety = | Cavendish | GrosMichel | Manzano type CherryVariety = | Montmorency | Bing This can be read as: • An AppleVariety is either a GoldenDelicious or a GrannySmith or a Fuji, and so on. @ScottWlaschin Jargon Alert: “Product Types” and “Sum Types” The types that are built using AND are called product types. The types that are built using OR are called sum types or tagged unions or, in F# terminology, discriminated unions. In this book I will often call them choice types, because I think that best describes their role in domain modeling.
  • 4. @philip_schwarz Let’s translate that F# example into Haskell, Scala and Java.
  • 5. data FruitSalad = FruitSalad { apple :: AppleVariety, banana :: BananaVariety, cherries :: CherryVariety } data FruitSnack = Apple AppleVariety | Banana BananaVariety | Cherries CherryVariety data AppleVariety = GoldenDelicious | GrannySmith | Fuji data BananaVariety = Cavendish | GrosMichel | Manzano data CherryVariety = Montmorency | Bing case class FruitSalad( apple: AppleVariety, banana: BananaVariety, cherries: CherryVariety ) enum FruitSnack: case Apple(variety: AppleVariety) case Banana(variety: BananaVariety) case Cherries(variety: CherryVariety) enum AppleVariety: case GoldenDelicious, GrannySmith, Fuji enum BananaVariety: case Cavendish, GrosMichel, Manzano enum CherryVariety: case Montmorency, Bing record FruitSalad( AppleVariety apple, BananaVariety banana, CherryVariety cherries ) { } sealed interface FruitSnack permits Apple, Banana, Cherries { } record Apple(AppleVariety variety) implements FruitSnack { } record Banana(BananaVariety variety) implements FruitSnack { } record Cherries(CherryVariety variety) implements FruitSnack { } enum AppleVariety { GOLDEN_DELICIOUS, GRANNY_SMITH, FUJI} enum BananaVariety { CAVENDISH, GROS_MICHEL, MANZANO} enum CherryVariety { MONTMORENCY, BING}
  • 6. Now, let’s see what the behaviour is when we compare sample values and when we convert them to strings.
  • 7. data FruitSalad = FruitSalad { apple :: AppleVariety, banana :: BananaVariety, cherries :: CherryVariety } deriving (Eq, Show) data FruitSnack = Apple AppleVariety | Banana BananaVariety | Cherries CherryVariety deriving (Eq, Show) data AppleVariety = GoldenDelicious | GrannySmith | Fuji deriving (Eq, Show) data BananaVariety = Cavendish | GrosMichel | Manzano deriving (Eq, Show) data CherryVariety = Montmorency | Bing deriving (Eq, Show) main :: IO () main = let salad = FruitSalad GoldenDelicious Cavendish Montmorency sameSalad = FruitSalad GoldenDelicious Cavendish Montmorency differentSalad = FruitSalad GoldenDelicious Manzano Montmorency snack = Apple GoldenDelicious sameSnack = Apple GoldenDelicious differentSnack = Banana Cavendish in do assert (show salad == "FruitSalad {apple = GoldenDelicious, banana = Cavendish, cherries = Montmorency}") pure () assert (salad == sameSalad) return () assert (salad /= differentSalad) return () assert (show snack == "Apple GoldenDelicious") return () assert (snack == sameSnack) return () assert (snack /= differentSnack) return () -- Error: Couldn't match expected type ‘FruitSalad’ with actual type ‘FruitSnack’ assert(snack /= salad) return () -- Error: Couldn't match expected type ‘FruitSnack’ with actual type ‘AppleVariety’ assert(snack /= GoldenDelicious) return () -- Error: Couldn't match expected type ‘FruitSnack’ with actual type ‘AppleVariety’ assert(salad /= GoldenDelicious) return () To permit the ‘showing’ of FruitSalad and FruitSnack values, and also to permit the comparison of such values, we have added the following to all types: deriving (Eq, Show).
  • 8. val salad = FruitSalad(GoldenDelicious, Cavendish, Montmorency); val sameSalad = FruitSalad(GoldenDelicious, Cavendish, Montmorency); val differentSalad = FruitSalad(GoldenDelicious, Manzano, Montmorency); val snack = Apple(GoldenDelicious) val sameSnack = Apple(GoldenDelicious) val differentSnack = Banana(Cavendish) assert(salad.toString == "FruitSalad(GoldenDelicious,Cavendish,Montmorency)") assert(salad == sameSalad) assert(salad != differentSalad) assert(snack.toString == "Apple(GoldenDelicious)") assert(snack == sameSnack); assert(snack != differentSnack); // Compiler error: Values of types FruitSalad and FruitSnack cannot be compared with == or != assert(salad != snack) // Compiler error: Values of types FruitSalad and AppleVariety cannot be compared with == or != assert(salad != GoldenDelicious) // Compiler error: Values of types FruitSnack and AppleVariety cannot be compared with == or != assert(snack != GoldenDelicious) case class FruitSalad( apple: AppleVariety, banana: BananaVariety, cherries: CherryVariety ) derives CanEqual enum FruitSnack derives CanEqual: case Apple(variety: AppleVariety) case Banana(variety: BananaVariety) case Cherries(variety: CherryVariety) enum AppleVariety: case GoldenDelicious, GrannySmith, Fuji enum BananaVariety: case Cavendish, GrosMichel, Manzano enum CherryVariety: case Montmorency, Bing To prevent meaningless comparisons, e.g. comparing a salad with a snack, we have added the following to FruitSalad and FruitSnack: derives CanEqual.
  • 9. case class FruitSalad( apple: AppleVariety, banana: BananaVariety, cherries: CherryVariety ) derives CanEqual enum FruitSnack derives CanEqual: case Apple(variety: AppleVariety) case Banana(variety: BananaVariety) case Cherries(variety: CherryVariety) enum AppleVariety: case GoldenDelicious, GrannySmith, Fuji enum BananaVariety: case Cavendish, GrosMichel, Manzano enum CherryVariety: case Montmorency, Bing products (AND) degenerate products - single argument product (AND) sum (OR)
  • 10. record FruitSalad( AppleVariety apple, BananaVariety banana, CherryVariety cherries ) { } sealed interface FruitSnack permits Apple, Banana, Cherries { } record Apple(AppleVariety variety) implements FruitSnack { } record Banana(BananaVariety variety) implements FruitSnack { } record Cherries(CherryVariety variety) implements FruitSnack { } enum AppleVariety { GOLDEN_DELICIOUS, GRANNY_SMITH, FUJI} enum BananaVariety { CAVENDISH, GROS_MICHEL, MANZANO} enum CherryVariety { MONTMORENCY, BING} var salad = new FruitSalad(GOLDEN_DELICIOUS,CAVENDISH, MONTMORENCY); var sameSalad = new FruitSalad(GOLDEN_DELICIOUS,CAVENDISH, MONTMORENCY); var differentSalad = new FruitSalad(GOLDEN_DELICIOUS,MANZANO, MONTMORENCY); var snack = new Apple(GOLDEN_DELICIOUS); var sameSnack = new Apple(GOLDEN_DELICIOUS); var differentSnack = new Banana(CAVENDISH); assert(salad.toString().equals("FruitSalad[apple=GOLDEN_DELICIOUS, banana=CAVENDISH, cherries=MONTMORENCY]")); assert(salad.equals(sameSalad)); assert(!salad.equals(differentSalad)); assert(snack.toString().equals("Apple[variety=GOLDEN_DELICIOUS]")); assert(snack.equals(sameSnack)); assert(!snack.equals(differentSnack)); assert(!salad.equals(snack)); assert(!salad.equals(GOLDEN_DELICIOUS)); assert(!snack.equals(GOLDEN_DELICIOUS));
  • 11. Now, let’s see some pattern matching @philip_schwarz
  • 12. pickyCustomerReaction :: FruitSalad -> String pickyCustomerReaction (FruitSalad Fuji Cavendish Bing) = "That's my favourite combination." pickyCustomerReaction (FruitSalad GoldenDelicious _ _) = "I can't stand Golden Delicious apples." pickyCustomerReaction (FruitSalad _ Manzano Bing) = "I both love and hate this." pickyCustomerReaction (FruitSalad _ Manzano _) = "Manzano is my least favourite banana." pickyCustomerReaction (FruitSalad _ _ Bing) = "Bing are my favourite cherries." pickyCustomerReaction _ = "It will do." data FruitSalad = FruitSalad { apple :: AppleVariety, banana :: BananaVariety, cherries :: CherryVariety } deriving (Eq, Show) data FruitSnack = Apple AppleVariety | Banana BananaVariety | Cherries CherryVariety deriving (Eq, Show) data AppleVariety = GoldenDelicious | GrannySmith | Fuji deriving (Eq, Show) data BananaVariety = Cavendish | GrosMichel | Manzano deriving (Eq, Show) data CherryVariety = Montmorency | Bing deriving (Eq, Show) pickySnackerRemark :: FruitSnack -> String pickySnackerRemark (Apple Fuji) = "That's my favourite apple." pickySnackerRemark (Apple GoldenDelicious) = "I can't stand Golden Delicious apples." pickySnackerRemark (Banana Cavendish) = "That's my favourite banana." pickySnackerRemark (Banana Manzano) = "Manzano is my least favourite banana." pickySnackerRemark (Cherries Bing) = "Those are my favourite cherries." pickySnackerRemark _ = "It will do."
  • 13. case class FruitSalad( apple: AppleVariety, banana: BananaVariety, cherries: CherryVariety ) enum FruitSnack: case Apple(variety: AppleVariety) case Banana(variety: BananaVariety) case Cherries(variety: CherryVariety) enum AppleVariety: case GoldenDelicious, GrannySmith, Fuji enum BananaVariety: case Cavendish, GrosMichel, Manzano enum CherryVariety: case Montmorency, Bing val pickyCustomerReaction = salad match case FruitSalad(Fuji,Cavendish,Bing) => "That's my favourite combination." case FruitSalad(GoldenDelicious,_,_) => "I can't stand Golden Delicious apples.” case FruitSalad(_,Manzano,Bing) => "I both love and hate this." case FruitSalad(_,Manzano,_) => "Manzano is my least favourite banana." case FruitSalad(_,_,Bing) => "Bing are my favourite cherries." case _ => "It will do." val pickySnackerRemark = snack match case Apple(Fuji) => "That's my favourite apple." case Apple(GoldenDelicious) => "I can't stand Golden Delicious apples." case Banana(Cavendish) => "That's my favourite banana." case Banana(Manzano) => "Manzano is my least favourite banana." case Cherries(Bing) => "Those are my favourite cherries." case _ => "It will do."
  • 14. record FruitSalad( AppleVariety apple, BananaVariety banana, CherryVariety cherries ) { } sealed interface FruitSnack permits Apple, Banana, Cherries { } record Apple(AppleVariety variety) implements FruitSnack { } record Banana(BananaVariety variety) implements FruitSnack { } record Cherries(CherryVariety variety) implements FruitSnack { } enum AppleVariety { GOLDEN_DELICIOUS, GRANNY_SMITH, FUJI} enum BananaVariety { CAVENDISH, GROS_MICHEL, MANZANO} enum CherryVariety { MONTMORENCY, BING} String pickyCustomerReaction(FruitSalad salad) { return switch (salad) { case FruitSalad(var apple, var banana, var cherries) when apple.equals(FUJI) && banana.equals(CAVENDISH) && cherries.equals(BING) -> "That's my favourite combination."; case FruitSalad(var apple, var banana, var cherries) when apple.equals(GOLDEN_DELICIOUS) -> "I can't stand Golden Delicious apples."; case FruitSalad(var apple, var banana, var cherries) when banana.equals(MANZANO) && cherries.equals(BING) -> "I both love and hate this."; case FruitSalad(var apple, var banana, var cherries) when banana.equals(MANZANO) -> "Manzano is my least favourite banana."; case FruitSalad(var apple, var banana, var cherries) when cherries.equals(BING) -> "Bing are my favourite cherries."; default -> "It will do."; }; } String pickySnackerRemark(FruitSnack snack) { return switch (snack) { case Apple(var variety) when variety.equals(FUJI) ->"That's my favourite apple."; case Apple(var variety) when variety.equals(GOLDEN_DELICIOUS) ->"I can't stand Golden Delicious apples."; case Banana(var variety) when variety.equals(CAVENDISH) ->"That's my favourite banana."; case Banana(var variety) when variety.equals(MANZANO) ->"Manzano is my least favourite banana."; case Cherries(var variety) when variety.equals(BING) ->"Those are my favourite cherries."; default -> "It will do."; }; }
  • 15. In order to run that pattern matching code, I downloaded the Java 19 early access build.
  • 16. $ ~/Downloads/jdk-19.jdk/Contents/Home/bin/jshell --enable-preview | Welcome to JShell -- Version 19-ea | For an introduction type: /help intro jshell> record FruitSalad( ...> AppleVariety apple, ...> BananaVariety banana, ...> CherryVariety cherries ...> ) { } ...> ...> sealed interface FruitSnack permits Apple, Banana, Cherries { } ...> record Apple(AppleVariety variety) implements FruitSnack { } ...> record Banana(BananaVariety variety) implements FruitSnack { } ...> record Cherries(CherryVariety variety) implements FruitSnack { } ...> ...> enum AppleVariety {GOLDEN_DELICIOUS, GRANNY_SMITH, FUJI} ...> enum BananaVariety {CAVENDISH, GROS_MICHEL, MANZANO} ...> enum CherryVariety {MONTMORENCY, BING} | created record FruitSalad, however, it cannot be referenced until class AppleVariety, class BananaVariety, and class CherryVariety are declared | created interface FruitSnack, however, it cannot be referenced until class Apple, class Banana, and class Cherries are declared | created record Apple, however, it cannot be referenced until class AppleVariety is declared | created record Banana, however, it cannot be referenced until class BananaVariety is declared | created record Cherries, however, it cannot be referenced until class CherryVariety is declared | created enum AppleVariety | created enum BananaVariety | created enum CherryVariety jshell>
  • 17. jshell> String pickySnackerRemark(FruitSnack snack) { ...> return switch (snack) { ...> case Apple(var variety) when variety.equals(AppleVariety.FUJI) ->"That's my favourite apple."; ...> case Apple(var variety) when variety.equals(AppleVariety.GOLDEN_DELICIOUS) ->"I can't stand Golden Delicious apples."; ...> case Banana(var variety) when variety.equals(BananaVariety.CAVENDISH) ->"That's my favourite banana."; ...> case Banana(var variety) when variety.equals(BananaVariety.MANZANO) ->"Manzano is my least favourite banana."; ...> case Cherries(var variety) when variety.equals(CherryVariety.BING) ->"Those are my favourite cherries."; ...> default -> "It will do."; ...> }; ...> } | created method pickySnackerRemark(FruitSnack) jshell> FruitSnack snack = new Banana(BananaVariety.MANZANO); snack ==> Banana[variety=MANZANO] jshell> pickySnackerRemark(snack) $11 ==> "Manzano is my least favourite banana.” jshell>
  • 18. jshell> String pickyCustomerReaction(FruitSalad salad) { ...> return switch (salad) { ...> case FruitSalad(var apple, var banana , var cherries) ...> when apple.equals(AppleVariety.FUJI) && banana.equals(BananaVariety.CAVENDISH) && cherries.equals(CherryVariety.BING) -> ...> "That's my favourite combination."; ...> case FruitSalad(var apple, var banana , var cherries) ...> when apple.equals(AppleVariety.GOLDEN_DELICIOUS) -> ...> "I can't stand Golden Delicious apples."; ...> case FruitSalad(var apple, var banana , var cherries) ...> when banana.equals(BananaVariety.MANZANO) -> ...> "Manzano is my least favourite banana."; ...> case FruitSalad(var apple, var banana , var cherries) ...> when cherries.equals(CherryVariety.BING) -> ...> "Bing are my favourite cherries."; ...> case FruitSalad(var apple, var banana , var cherries) ...> when banana.equals(BananaVariety.MANZANO) && cherries.equals(CherryVariety.BING) -> ...> "I both love and hate this."; ...> default -> "It will do."; ...> }; ...> } | created method pickyCustomerReaction(FruitSalad) jshell> var salad = new FruitSalad(AppleVariety.GOLDEN_DELICIOUS,BananaVariety.CAVENDISH, CherryVariety.MONTMORENCY); salad ==> FruitSalad[apple=GOLDEN_DELICIOUS, banana=CAVENDISH, cherries=MONTMORENCY] jshell> pickyCustomerReaction(salad); $14 ==> "I can't stand Golden Delicious apples." jshell>
  • 19. I had a go at applying those suggestions. The first one was fine. When I tried the second one, I ran into some issues. If I find out more from Brian Goetz, or I manage to resolve the issue, then I’ll publish a new version of this deck.
  • 20. That’s all. I hope you found it useful. @philip_schwarz
  翻译: