SlideShare a Scribd company logo
1 of 13
Download to read offline
Functional Core and Imperative Shell
Game of Life Example
See a program structure flowchart used to highlight how an FP program breaks down into a functional core and imperative shell
View a program structure flowchart for the Game of Life
See the code for Game of Life’s functional core and imperative shell, both in Haskell and in Scala
Polyglot FP for Fun and Profit – Haskell and Scala
Graham Hutton
@haskellhutt @VBragilevsky
Vitaly Bragilevsky
𝜆
functional	
core
imperative
shell
@philip_schwarz
slides by https://www.slideshare.net/pjschwarz
In Haskell in Depth, Vitaly Bragilevsky visualises certain aspects of his programs using program structure flowcharts.
One of the things shown by his diagrams is how the programs break down into a pure part and an I/O part, i.e. into a
functional core and an imperative shell.
In this short slide deck we do the following:
• create a program structure flowchart for the Game of Life
• show how Game of Life code consists of a functional core and an imperative shell
@philip_schwarz
@VBragilevsky
• User input is represented by parallelograms.
• All functions are represented by rectangles.
• Some of the functions are executing I/O actions. These are shown in the central part of the flowchart.
• Other functions are pure. They are given on the right-hand side.
• Diamonds traditionally represent choices made within a program.
• Function calls are represented by rectangles below and to the right of a caller.
• Several calls within a function are combined with a dashed line.
• Arrows in this flowchart represent moving data between the user and the program and between functions within the program.
READING A PROGRAM STRUCTURE FLOWCHART
I’ve tried to present all the components of the program in a program
structure flowchart: user input, actions in the I/O part of the program,
and their relations with the pure functions. I use the following notation
Vitaly Bragilevsky
If you would like an introduction to the notion of ’functional core, imperative shell’, see slides 15-20 of the second slide deck below.
If you want an explanation of the Game of Life code that we’ll be looking at next, see the first slide deck for Haskell, and the remaining two for Scala.
OOO OOO
O O O O
O O O O
O O O O
OOO OOO
OOO OOO
O O O O
O O O O
O O O O
OOO OOO
O O
O O
OO OO
OOO OO OO OOO
O O O O O O
OO OO
OO OO
O O O O O O
OOO OO OO OOO
OO OO
O O
O O
OO OO
OO OO
O O O O O O
OOO OO OO OOO
O O O O O O
OOO OOO
OOO OOO
O O O O O O
OOO OO OO OOO
O O O O O O
OO OO
OO OO
If we run the upcoming Game of Life program with a 20 by 20
board configured with the first generation of a Pulsar, the
program cycles forever through the following three patterns
pulsar :: Board
pulsar =
[(4, 2),(5, 2),(6, 2),(10, 2),(11, 2),(12, 2),
(2, 4),(7, 4),( 9, 4),(14, 4),
(2, 5),(7, 5),( 9, 5),(14, 5),
(2, 6),(7, 6),( 9, 6),(14, 6),
(4, 7),(5, 7),(6, 7),(10, 7),(11, 7),(12, 7),
(4, 9),(5, 9),(6, 9),(10, 9),(11, 9),(12, 9),
(2,10),(7,10),( 9,10),(14,10),
(2,11),(7,11),( 9,11),(14,11),
(2,12),(7,12),( 9,12),(14,12),
(4,14),(5,14),(6,14),(10,14),(11,14),(12,14)]
type Pos = (Int,Int) width :: Int
width = 20
type Board = [Pos] height :: Int
height = 20
The next slide shows a simple program structure flowchart for the Game of Life
program.
The rest of the slides show the following:
1. Haskell code for the program’s imperative shell
2. Haskell code for its functional core
3. .structure flowchart for the program (Scala version)
4. .Scala code for the imperative shell
5. .Scala code for the functional core
The Haskell Game of Life code is the one found in Graham Hutton’s book, Programming
in Haskell, with a handful of very minor changes, e.g.
• added an extra invocation of a function in order to move the cursor out of the way
after drawing a generation
• added data for the first pulsar generation
User Input I/O part Pure part
main
cls
showcells
nextgen
life
clears screen
prints cells to screen
wait
main :: IO ()
main = life(pulsar)
nextgen :: Board -> Board
showcells :: Board -> IO ()
cls :: IO ()
wait :: Int -> IO ()
life :: Board -> IO ()
life b = do
cls
showcells b
goto (width+1,height+1)
wait 500000
life (nextgen b)
FUNCTIONAL CORE
IMPERATIVE SHELL
goto moves cursor to bottom right
goto :: Pos -> IO ()
Graham Hutton
@haskellhutt
cls :: IO ()
cls = putStr "ESC[2J"
showcells :: Board -> IO ()
showcells b = sequence_ [writeat p "O" | p <- b]
wait :: Int -> IO ()
wait n = sequence_ [return () | _ <- [1..n]]
main :: IO ()
main = life(pulsar)
life :: Board -> IO ()
life b = do cls
showcells b
goto (width + 1, height + 1)
wait 500000
life (nextgen b)
writeat :: Pos -> String -> IO ()
writeat p xs = do goto p
putStr xs
goto :: Pos -> IO ()
goto (x,y) =
putStr ("ESC[" ++ show y ++ ";"
++ show x ++ "H")
putStr :: String -> IO ()
putStr [] = return ()
putStr (x:xs) = do putChar x
putStr xs
IMPERATIVE SHELL
Graham Hutton
@haskellhutt
nextgen :: Board -> Board
nextgen b = survivors b ++ births b
survivors :: Board -> [Pos]
survivors b =
[p | p <- b,
elem (liveneighbs b p) [2,3]]
births :: Board -> [Pos]
births b = [p | p <- rmdups (concat (map neighbs b)),
isEmpty b p,
liveneighbs b p == 3]
neighbs :: Pos -> [Pos]
neighbs (x,y) = map wrap [(x-1, y-1), (x, y-1),
(x+1, y-1), (x-1, y ),
(x+1, y), (x-1, y+1),
(x, y+1), (x+1, y+1)]
wrap :: Pos -> Pos
wrap (x,y) = (((x-1) `mod` width) + 1,
((y-1) `mod` height) + 1)
width :: Int height :: Int
width = 20 height = 20
rmdups :: Eq a => [a] -> [a]
rmdups [] = []
rmdups (x:xs) = x : rmdups (filter (/= x) xs)
isEmpty :: Board -> Pos -> Bool
isEmpty b p = not (isAlive b p)
liveneighbs :: Board -> Pos -> Int
liveneighbs b = length.filter(isAlive b).neighbs
isAlive :: Board -> Pos -> Bool
isAlive b p = elem p b
pulsar :: Board
pulsar =
[(4, 2),(5, 2),(6, 2),(10, 2),(11, 2),(12, 2),
(2, 4),(7, 4),( 9, 4),(14, 4),
(2, 5),(7, 5),( 9, 5),(14, 5),
(2, 6),(7, 6),( 9, 6),(14, 6),
(4, 7),(5, 7),(6, 7),(10, 7),(11, 7),(12, 7),
(4, 9),(5, 9),(6, 9),(10, 9),(11, 9),(12, 9),
(2,10),(7,10),( 9,10),(14,10),
(2,11),(7,11),( 9,11),(14,11),
(2,12),(7,12),( 9,12),(14,12),
(4,14),(5,14),(6,14),(10,14),(11,14),(12,14)]
type Pos = (Int,Int)
type Board = [Pos]
FUNCTIONAL CORE
User Input I/O part Pure part
main
cls
showcells
nextgen
life
clears screen
prints cells to screen
wait
def nextgen(b:Board):Board
FUNCTIONAL CORE
IMPERATIVE SHELL
goto moves cursor to bottom right
def showCells(b: Board): IO[Unit]
def cls: IO[Unit]
def wait(n:Int): IO[Unit]
def life(b: Board): IO[Unit] =
cls *>
showCells(b) *>
goto(width+1,height+1) *>
wait(1_000_000) >>
life(nextgen(b))
val main: IO[Unit] =
life(pulsar)
def goto(p: Pos): IO[Unit]
val main: IO[Unit] = life(pulsar)
def life(b: Board): IO[Unit] =
cls *>
showCells(b) *>
goto(width+1,height+1) *>
wait(1_000_000) >>
life(nextgen(b))
def cls: IO[Unit] = putStr("u001B[2J")
def showCells(b: Board): IO[Unit] =
( for { p <- b } yield writeAt(p, "O") ).sequence_
def wait(n:Int): IO[Unit] = List.fill(n)(IO.unit).sequence_
def writeAt(p: Pos, s: String): IO[Unit] =
goto(p) *> putStr(s)
def goto(p: Pos): IO[Unit] = p match {
case (x,y) => putStr(s"u001B[${y};${x}H")
}
def putStr(s: String): IO[Unit] =
IO { scala.Predef.print(s) }
IMPERATIVE SHELL import cats.implicits._, cats.effect.IO
main.unsafeRunSync
def nextgen(b: Board): Board = survivors(b) ++ births(b)
def survivors(b: Board): List[Pos] =
for {
p <- b
if List(2,3) contains liveneighbs(b)(p)
} yield p
def births(b: Board): List[Pos] =
for {
p <- rmdups(b flatMap neighbs)
if isEmpty(b)(p)
if liveneighbs(b)(p) == 3
} yield p
def rmdups[A](l: List[A]): List[A] = l match {
case Nil => Nil
case x::xs => x::rmdups(xs filter(_ != x)) }
def isEmpty(b: Board)(p: Pos): Boolean =
!(isAlive(b)(p))
def liveneighbs(b: Board)(p: Pos): Int =
neighbs(p).filter(isAlive(b)).length
def isAlive(b: Board)(p: Pos): Boolean =
b contains p
def neighbs(p: Pos): List[Pos] = p match {
case (x,y) => List(
(x - 1, y - 1), (x, y - 1), (x + 1, y - 1),
(x - 1, y ), /* cell */ (x + 1, y ),
(x - 1, y + 1), (x, y + 1), (x + 1, y + 1)
) map wrap }
def wrap(p: Pos): Pos = p match {
case (x, y) => (((x - 1) % width) + 1,
((y - 1) % height) + 1) }
val width = 20 val height = 20
val pulsar: Board = List(
(4, 2),(5, 2),(6, 2),(10, 2),(11, 2),(12, 2),
(2, 4),(7, 4),( 9, 4),(14, 4),
(2, 5),(7, 5),( 9, 5),(14, 5),
(2, 6),(7, 6),( 9, 6),(14, 6),
(4, 7),(5, 7),(6, 7),(10, 7),(11, 7),(12, 7),
(4, 9),(5, 9),(6, 9),(10, 9),(11, 9),(12, 9),
(2,10),(7,10),( 9,10),(14,10),
(2,11),(7,11),( 9,11),(14,11),
(2,12),(7,12),( 9,12),(14,12),
(4,14),(5,14),(6,14),(10,14),(11,14),(12,14)])
FUNCTIONAL CORE
type Pos = (Int, Int)
type Board = List[Pos]
If you want to run the programs, you can find them here:
• https://github.com/philipschwarz/functional-core-imperative-shell-scala
• https://github.com/philipschwarz/functional-core-imperative-shell-haskell
That’s all.
I hope you found it useful.
See you soon.
@philip_schwarz

More Related Content

What's hot

Hivemall v0.3の機能紹介@1st Hivemall meetup
Hivemall v0.3の機能紹介@1st Hivemall meetupHivemall v0.3の機能紹介@1st Hivemall meetup
Hivemall v0.3の機能紹介@1st Hivemall meetup
Makoto Yui
 

What's hot (20)

Refactoring: A First Example - Martin Fowler’s First Example of Refactoring, ...
Refactoring: A First Example - Martin Fowler’s First Example of Refactoring, ...Refactoring: A First Example - Martin Fowler’s First Example of Refactoring, ...
Refactoring: A First Example - Martin Fowler’s First Example of Refactoring, ...
 
One Monad to Rule Them All
One Monad to Rule Them AllOne Monad to Rule Them All
One Monad to Rule Them All
 
Sum and Product Types - The Fruit Salad & Fruit Snack Example - From F# to Ha...
Sum and Product Types -The Fruit Salad & Fruit Snack Example - From F# to Ha...Sum and Product Types -The Fruit Salad & Fruit Snack Example - From F# to Ha...
Sum and Product Types - The Fruit Salad & Fruit Snack Example - From F# to Ha...
 
Algebraic Data Types for Data Oriented Programming - From Haskell and Scala t...
Algebraic Data Types forData Oriented Programming - From Haskell and Scala t...Algebraic Data Types forData Oriented Programming - From Haskell and Scala t...
Algebraic Data Types for Data Oriented Programming - From Haskell and Scala t...
 
Tagless Final Encoding - Algebras and Interpreters and also Programs
Tagless Final Encoding - Algebras and Interpreters and also ProgramsTagless Final Encoding - Algebras and Interpreters and also Programs
Tagless Final Encoding - Algebras and Interpreters and also Programs
 
サーバーサイド Kotlin のテストフレームワーク事情
サーバーサイド Kotlin のテストフレームワーク事情サーバーサイド Kotlin のテストフレームワーク事情
サーバーサイド Kotlin のテストフレームワーク事情
 
75% code coverage in Unity: How to create testable architecture / Andrew Vish...
75% code coverage in Unity: How to create testable architecture / Andrew Vish...75% code coverage in Unity: How to create testable architecture / Andrew Vish...
75% code coverage in Unity: How to create testable architecture / Andrew Vish...
 
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
 
Embree Ray Tracing Kernels
Embree Ray Tracing KernelsEmbree Ray Tracing Kernels
Embree Ray Tracing Kernels
 
Rundown of Async/Await in Rust
Rundown of Async/Await in RustRundown of Async/Await in Rust
Rundown of Async/Await in Rust
 
Hivemall v0.3の機能紹介@1st Hivemall meetup
Hivemall v0.3の機能紹介@1st Hivemall meetupHivemall v0.3の機能紹介@1st Hivemall meetup
Hivemall v0.3の機能紹介@1st Hivemall meetup
 
Quicksort - a whistle-stop tour of the algorithm in five languages and four p...
Quicksort - a whistle-stop tour of the algorithm in five languages and four p...Quicksort - a whistle-stop tour of the algorithm in five languages and four p...
Quicksort - a whistle-stop tour of the algorithm in five languages and four p...
 
ZIO Queue
ZIO QueueZIO Queue
ZIO Queue
 
圏とHaskellの型
圏とHaskellの型圏とHaskellの型
圏とHaskellの型
 
Domain Driven Design with the F# type System -- F#unctional Londoners 2014
Domain Driven Design with the F# type System -- F#unctional Londoners 2014Domain Driven Design with the F# type System -- F#unctional Londoners 2014
Domain Driven Design with the F# type System -- F#unctional Londoners 2014
 
社内ソフトスキルを考える
社内ソフトスキルを考える社内ソフトスキルを考える
社内ソフトスキルを考える
 
Beyond porting
Beyond portingBeyond porting
Beyond porting
 
Error Management: Future vs ZIO
Error Management: Future vs ZIOError Management: Future vs ZIO
Error Management: Future vs ZIO
 
Point free or die - tacit programming in Haskell and beyond
Point free or die - tacit programming in Haskell and beyondPoint free or die - tacit programming in Haskell and beyond
Point free or die - tacit programming in Haskell and beyond
 
FlutterでGraphQLを扱う
FlutterでGraphQLを扱うFlutterでGraphQLを扱う
FlutterでGraphQLを扱う
 

Similar to Functional Core and Imperative Shell - Game of Life Example - Haskell and Scala

Refactoring to Macros with Clojure
Refactoring to Macros with ClojureRefactoring to Macros with Clojure
Refactoring to Macros with Clojure
Dmitry Buzdin
 
Modular Module Systems
Modular Module SystemsModular Module Systems
Modular Module Systems
league
 

Similar to Functional Core and Imperative Shell - Game of Life Example - Haskell and Scala (20)

Game of Life - Polyglot FP - Haskell, Scala, Unison - Part 2 - with minor cor...
Game of Life - Polyglot FP - Haskell, Scala, Unison - Part 2 - with minor cor...Game of Life - Polyglot FP - Haskell, Scala, Unison - Part 2 - with minor cor...
Game of Life - Polyglot FP - Haskell, Scala, Unison - Part 2 - with minor cor...
 
Byterun, a Python bytecode interpreter - Allison Kaptur at NYCPython
Byterun, a Python bytecode interpreter - Allison Kaptur at NYCPythonByterun, a Python bytecode interpreter - Allison Kaptur at NYCPython
Byterun, a Python bytecode interpreter - Allison Kaptur at NYCPython
 
T3chFest 2016 - The polyglot programmer
T3chFest 2016 - The polyglot programmerT3chFest 2016 - The polyglot programmer
T3chFest 2016 - The polyglot programmer
 
Future vs. Monix Task
Future vs. Monix TaskFuture vs. Monix Task
Future vs. Monix Task
 
Refactoring to Macros with Clojure
Refactoring to Macros with ClojureRefactoring to Macros with Clojure
Refactoring to Macros with Clojure
 
ES6: The future is now
ES6: The future is nowES6: The future is now
ES6: The future is now
 
Modular Module Systems
Modular Module SystemsModular Module Systems
Modular Module Systems
 
NetPonto - The Future Of C# - NetConf Edition
NetPonto - The Future Of C# - NetConf EditionNetPonto - The Future Of C# - NetConf Edition
NetPonto - The Future Of C# - NetConf Edition
 
Talk - Query monad
Talk - Query monad Talk - Query monad
Talk - Query monad
 
C cheat sheet for varsity (extreme edition)
C cheat sheet for varsity (extreme edition)C cheat sheet for varsity (extreme edition)
C cheat sheet for varsity (extreme edition)
 
A Few of My Favorite (Python) Things
A Few of My Favorite (Python) ThingsA Few of My Favorite (Python) Things
A Few of My Favorite (Python) Things
 
Javascript
JavascriptJavascript
Javascript
 
An Intro To ES6
An Intro To ES6An Intro To ES6
An Intro To ES6
 
Functional programming
Functional programmingFunctional programming
Functional programming
 
ECMAScript 6
ECMAScript 6ECMAScript 6
ECMAScript 6
 
Clojure Intro
Clojure IntroClojure Intro
Clojure Intro
 
Kotlin For Android - Functions (part 3 of 7)
Kotlin For Android - Functions (part 3 of 7)Kotlin For Android - Functions (part 3 of 7)
Kotlin For Android - Functions (part 3 of 7)
 
Stack
StackStack
Stack
 
ES6 and AngularAMD
ES6 and AngularAMDES6 and AngularAMD
ES6 and AngularAMD
 
Vcs23
Vcs23Vcs23
Vcs23
 

More from Philip Schwarz

N-Queens Combinatorial Puzzle meets Cats
N-Queens Combinatorial Puzzle meets CatsN-Queens Combinatorial Puzzle meets Cats
N-Queens Combinatorial Puzzle meets Cats
Philip Schwarz
 

More from Philip Schwarz (20)

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
 
Folding Cheat Sheet #4 - fourth in a series
Folding Cheat Sheet #4 - fourth in a seriesFolding Cheat Sheet #4 - fourth in a series
Folding Cheat Sheet #4 - fourth in a series
 
Folding Cheat Sheet #3 - third in a series
Folding Cheat Sheet #3 - third in a seriesFolding Cheat Sheet #3 - third in a series
Folding Cheat Sheet #3 - third in a series
 
Folding Cheat Sheet #2 - second in a series
Folding Cheat Sheet #2 - second in a seriesFolding Cheat Sheet #2 - second in a series
Folding Cheat Sheet #2 - second in a series
 
Folding Cheat Sheet #1 - first in a series
Folding Cheat Sheet #1 - first in a seriesFolding Cheat Sheet #1 - first in a series
Folding Cheat Sheet #1 - first in a series
 
Scala Left Fold Parallelisation - Three Approaches
Scala Left Fold Parallelisation- Three ApproachesScala Left Fold Parallelisation- Three Approaches
Scala Left Fold Parallelisation - Three Approaches
 
Fusing Transformations of Strict Scala Collections with Views
Fusing Transformations of Strict Scala Collections with ViewsFusing Transformations of Strict Scala Collections with Views
Fusing Transformations of Strict Scala Collections with Views
 
A sighting of traverse_ function in Practical FP in Scala
A sighting of traverse_ function in Practical FP in ScalaA sighting of traverse_ function in Practical FP in Scala
A sighting of traverse_ function in Practical FP in Scala
 
A sighting of traverseFilter and foldMap in Practical FP in Scala
A sighting of traverseFilter and foldMap in Practical FP in ScalaA sighting of traverseFilter and foldMap in Practical FP in Scala
A sighting of traverseFilter and foldMap in Practical FP in Scala
 
A sighting of sequence function in Practical FP in Scala
A sighting of sequence function in Practical FP in ScalaA sighting of sequence function in Practical FP in Scala
A sighting of sequence function in Practical FP in Scala
 
N-Queens Combinatorial Puzzle meets Cats
N-Queens Combinatorial Puzzle meets CatsN-Queens Combinatorial Puzzle meets Cats
N-Queens Combinatorial Puzzle meets Cats
 
Kleisli composition, flatMap, join, map, unit - implementation and interrelat...
Kleisli composition, flatMap, join, map, unit - implementation and interrelat...Kleisli composition, flatMap, join, map, unit - implementation and interrelat...
Kleisli composition, flatMap, join, map, unit - implementation and interrelat...
 
The aggregate function - from sequential and parallel folds to parallel aggre...
The aggregate function - from sequential and parallel folds to parallel aggre...The aggregate function - from sequential and parallel folds to parallel aggre...
The aggregate function - from sequential and parallel folds to parallel aggre...
 
Nat, List and Option Monoids - from scratch - Combining and Folding - an example
Nat, List and Option Monoids -from scratch -Combining and Folding -an exampleNat, List and Option Monoids -from scratch -Combining and Folding -an example
Nat, List and Option Monoids - from scratch - Combining and Folding - an example
 
Nat, List and Option Monoids - from scratch - Combining and Folding - an example
Nat, List and Option Monoids -from scratch -Combining and Folding -an exampleNat, List and Option Monoids -from scratch -Combining and Folding -an example
Nat, List and Option Monoids - from scratch - Combining and Folding - an example
 
The Sieve of Eratosthenes - Part II - Genuine versus Unfaithful Sieve - Haske...
The Sieve of Eratosthenes - Part II - Genuine versus Unfaithful Sieve - Haske...The Sieve of Eratosthenes - Part II - Genuine versus Unfaithful Sieve - Haske...
The Sieve of Eratosthenes - Part II - Genuine versus Unfaithful Sieve - Haske...
 
Jordan Peterson - The pursuit of meaning and related ethical axioms
Jordan Peterson - The pursuit of meaning and related ethical axiomsJordan Peterson - The pursuit of meaning and related ethical axioms
Jordan Peterson - The pursuit of meaning and related ethical axioms
 
Defining filter using (a) recursion (b) folding (c) folding with S, B and I c...
Defining filter using (a) recursion (b) folding (c) folding with S, B and I c...Defining filter using (a) recursion (b) folding (c) folding with S, B and I c...
Defining filter using (a) recursion (b) folding (c) folding with S, B and I c...
 
Defining filter using (a) recursion (b) folding with S, B and I combinators (...
Defining filter using (a) recursion (b) folding with S, B and I combinators (...Defining filter using (a) recursion (b) folding with S, B and I combinators (...
Defining filter using (a) recursion (b) folding with S, B and I combinators (...
 
The Sieve of Eratosthenes - Part 1 - with minor corrections
The Sieve of Eratosthenes - Part 1 - with minor correctionsThe Sieve of Eratosthenes - Part 1 - with minor corrections
The Sieve of Eratosthenes - Part 1 - with minor corrections
 

Recently uploaded

Jax, FL Admin Community Group 05.14.2024 Combined Deck
Jax, FL Admin Community Group 05.14.2024 Combined DeckJax, FL Admin Community Group 05.14.2024 Combined Deck
Jax, FL Admin Community Group 05.14.2024 Combined Deck
Marc Lester
 

Recently uploaded (20)

Food Delivery Business App Development Guide 2024
Food Delivery Business App Development Guide 2024Food Delivery Business App Development Guide 2024
Food Delivery Business App Development Guide 2024
 
BusinessGPT - Security and Governance for Generative AI
BusinessGPT  - Security and Governance for Generative AIBusinessGPT  - Security and Governance for Generative AI
BusinessGPT - Security and Governance for Generative AI
 
Abortion Pill Prices Jane Furse ](+27832195400*)[ 🏥 Women's Abortion Clinic i...
Abortion Pill Prices Jane Furse ](+27832195400*)[ 🏥 Women's Abortion Clinic i...Abortion Pill Prices Jane Furse ](+27832195400*)[ 🏥 Women's Abortion Clinic i...
Abortion Pill Prices Jane Furse ](+27832195400*)[ 🏥 Women's Abortion Clinic i...
 
Automate your OpenSIPS config tests - OpenSIPS Summit 2024
Automate your OpenSIPS config tests - OpenSIPS Summit 2024Automate your OpenSIPS config tests - OpenSIPS Summit 2024
Automate your OpenSIPS config tests - OpenSIPS Summit 2024
 
Optimizing Operations by Aligning Resources with Strategic Objectives Using O...
Optimizing Operations by Aligning Resources with Strategic Objectives Using O...Optimizing Operations by Aligning Resources with Strategic Objectives Using O...
Optimizing Operations by Aligning Resources with Strategic Objectives Using O...
 
Abortion Pill Prices Germiston ](+27832195400*)[ 🏥 Women's Abortion Clinic in...
Abortion Pill Prices Germiston ](+27832195400*)[ 🏥 Women's Abortion Clinic in...Abortion Pill Prices Germiston ](+27832195400*)[ 🏥 Women's Abortion Clinic in...
Abortion Pill Prices Germiston ](+27832195400*)[ 🏥 Women's Abortion Clinic in...
 
Abortion Clinic In Pretoria ](+27832195400*)[ 🏥 Safe Abortion Pills in Pretor...
Abortion Clinic In Pretoria ](+27832195400*)[ 🏥 Safe Abortion Pills in Pretor...Abortion Clinic In Pretoria ](+27832195400*)[ 🏥 Safe Abortion Pills in Pretor...
Abortion Clinic In Pretoria ](+27832195400*)[ 🏥 Safe Abortion Pills in Pretor...
 
Your Ultimate Web Studio for Streaming Anywhere | Evmux
Your Ultimate Web Studio for Streaming Anywhere | EvmuxYour Ultimate Web Studio for Streaming Anywhere | Evmux
Your Ultimate Web Studio for Streaming Anywhere | Evmux
 
Lessons Learned from Building a Serverless Notifications System.pdf
Lessons Learned from Building a Serverless Notifications System.pdfLessons Learned from Building a Serverless Notifications System.pdf
Lessons Learned from Building a Serverless Notifications System.pdf
 
Abortion Pill Prices Mthatha (@](+27832195400*)[ 🏥 Women's Abortion Clinic In...
Abortion Pill Prices Mthatha (@](+27832195400*)[ 🏥 Women's Abortion Clinic In...Abortion Pill Prices Mthatha (@](+27832195400*)[ 🏥 Women's Abortion Clinic In...
Abortion Pill Prices Mthatha (@](+27832195400*)[ 🏥 Women's Abortion Clinic In...
 
Jax, FL Admin Community Group 05.14.2024 Combined Deck
Jax, FL Admin Community Group 05.14.2024 Combined DeckJax, FL Admin Community Group 05.14.2024 Combined Deck
Jax, FL Admin Community Group 05.14.2024 Combined Deck
 
Microsoft365_Dev_Security_2024_05_16.pdf
Microsoft365_Dev_Security_2024_05_16.pdfMicrosoft365_Dev_Security_2024_05_16.pdf
Microsoft365_Dev_Security_2024_05_16.pdf
 
The Strategic Impact of Buying vs Building in Test Automation
The Strategic Impact of Buying vs Building in Test AutomationThe Strategic Impact of Buying vs Building in Test Automation
The Strategic Impact of Buying vs Building in Test Automation
 
Abortion Clinic In Johannesburg ](+27832195400*)[ 🏥 Safe Abortion Pills in Jo...
Abortion Clinic In Johannesburg ](+27832195400*)[ 🏥 Safe Abortion Pills in Jo...Abortion Clinic In Johannesburg ](+27832195400*)[ 🏥 Safe Abortion Pills in Jo...
Abortion Clinic In Johannesburg ](+27832195400*)[ 🏥 Safe Abortion Pills in Jo...
 
Weeding your micro service landscape.pdf
Weeding your micro service landscape.pdfWeeding your micro service landscape.pdf
Weeding your micro service landscape.pdf
 
OpenChain Webinar: AboutCode and Beyond - End-to-End SCA
OpenChain Webinar: AboutCode and Beyond - End-to-End SCAOpenChain Webinar: AboutCode and Beyond - End-to-End SCA
OpenChain Webinar: AboutCode and Beyond - End-to-End SCA
 
Evolving Data Governance for the Real-time Streaming and AI Era
Evolving Data Governance for the Real-time Streaming and AI EraEvolving Data Governance for the Real-time Streaming and AI Era
Evolving Data Governance for the Real-time Streaming and AI Era
 
Effective Strategies for Wix's Scaling challenges - GeeCon
Effective Strategies for Wix's Scaling challenges - GeeConEffective Strategies for Wix's Scaling challenges - GeeCon
Effective Strategies for Wix's Scaling challenges - GeeCon
 
architecting-ai-in-the-enterprise-apis-and-applications.pdf
architecting-ai-in-the-enterprise-apis-and-applications.pdfarchitecting-ai-in-the-enterprise-apis-and-applications.pdf
architecting-ai-in-the-enterprise-apis-and-applications.pdf
 
Auto Affiliate AI Earns First Commission in 3 Hours..pdf
Auto Affiliate  AI Earns First Commission in 3 Hours..pdfAuto Affiliate  AI Earns First Commission in 3 Hours..pdf
Auto Affiliate AI Earns First Commission in 3 Hours..pdf
 

Functional Core and Imperative Shell - Game of Life Example - Haskell and Scala

  • 1. Functional Core and Imperative Shell Game of Life Example See a program structure flowchart used to highlight how an FP program breaks down into a functional core and imperative shell View a program structure flowchart for the Game of Life See the code for Game of Life’s functional core and imperative shell, both in Haskell and in Scala Polyglot FP for Fun and Profit – Haskell and Scala Graham Hutton @haskellhutt @VBragilevsky Vitaly Bragilevsky 𝜆 functional core imperative shell @philip_schwarz slides by https://www.slideshare.net/pjschwarz
  • 2. In Haskell in Depth, Vitaly Bragilevsky visualises certain aspects of his programs using program structure flowcharts. One of the things shown by his diagrams is how the programs break down into a pure part and an I/O part, i.e. into a functional core and an imperative shell. In this short slide deck we do the following: • create a program structure flowchart for the Game of Life • show how Game of Life code consists of a functional core and an imperative shell @philip_schwarz
  • 3. @VBragilevsky • User input is represented by parallelograms. • All functions are represented by rectangles. • Some of the functions are executing I/O actions. These are shown in the central part of the flowchart. • Other functions are pure. They are given on the right-hand side. • Diamonds traditionally represent choices made within a program. • Function calls are represented by rectangles below and to the right of a caller. • Several calls within a function are combined with a dashed line. • Arrows in this flowchart represent moving data between the user and the program and between functions within the program. READING A PROGRAM STRUCTURE FLOWCHART I’ve tried to present all the components of the program in a program structure flowchart: user input, actions in the I/O part of the program, and their relations with the pure functions. I use the following notation Vitaly Bragilevsky
  • 4. If you would like an introduction to the notion of ’functional core, imperative shell’, see slides 15-20 of the second slide deck below. If you want an explanation of the Game of Life code that we’ll be looking at next, see the first slide deck for Haskell, and the remaining two for Scala.
  • 5. OOO OOO O O O O O O O O O O O O OOO OOO OOO OOO O O O O O O O O O O O O OOO OOO O O O O OO OO OOO OO OO OOO O O O O O O OO OO OO OO O O O O O O OOO OO OO OOO OO OO O O O O OO OO OO OO O O O O O O OOO OO OO OOO O O O O O O OOO OOO OOO OOO O O O O O O OOO OO OO OOO O O O O O O OO OO OO OO If we run the upcoming Game of Life program with a 20 by 20 board configured with the first generation of a Pulsar, the program cycles forever through the following three patterns pulsar :: Board pulsar = [(4, 2),(5, 2),(6, 2),(10, 2),(11, 2),(12, 2), (2, 4),(7, 4),( 9, 4),(14, 4), (2, 5),(7, 5),( 9, 5),(14, 5), (2, 6),(7, 6),( 9, 6),(14, 6), (4, 7),(5, 7),(6, 7),(10, 7),(11, 7),(12, 7), (4, 9),(5, 9),(6, 9),(10, 9),(11, 9),(12, 9), (2,10),(7,10),( 9,10),(14,10), (2,11),(7,11),( 9,11),(14,11), (2,12),(7,12),( 9,12),(14,12), (4,14),(5,14),(6,14),(10,14),(11,14),(12,14)] type Pos = (Int,Int) width :: Int width = 20 type Board = [Pos] height :: Int height = 20
  • 6. The next slide shows a simple program structure flowchart for the Game of Life program. The rest of the slides show the following: 1. Haskell code for the program’s imperative shell 2. Haskell code for its functional core 3. .structure flowchart for the program (Scala version) 4. .Scala code for the imperative shell 5. .Scala code for the functional core The Haskell Game of Life code is the one found in Graham Hutton’s book, Programming in Haskell, with a handful of very minor changes, e.g. • added an extra invocation of a function in order to move the cursor out of the way after drawing a generation • added data for the first pulsar generation
  • 7. User Input I/O part Pure part main cls showcells nextgen life clears screen prints cells to screen wait main :: IO () main = life(pulsar) nextgen :: Board -> Board showcells :: Board -> IO () cls :: IO () wait :: Int -> IO () life :: Board -> IO () life b = do cls showcells b goto (width+1,height+1) wait 500000 life (nextgen b) FUNCTIONAL CORE IMPERATIVE SHELL goto moves cursor to bottom right goto :: Pos -> IO ()
  • 8. Graham Hutton @haskellhutt cls :: IO () cls = putStr "ESC[2J" showcells :: Board -> IO () showcells b = sequence_ [writeat p "O" | p <- b] wait :: Int -> IO () wait n = sequence_ [return () | _ <- [1..n]] main :: IO () main = life(pulsar) life :: Board -> IO () life b = do cls showcells b goto (width + 1, height + 1) wait 500000 life (nextgen b) writeat :: Pos -> String -> IO () writeat p xs = do goto p putStr xs goto :: Pos -> IO () goto (x,y) = putStr ("ESC[" ++ show y ++ ";" ++ show x ++ "H") putStr :: String -> IO () putStr [] = return () putStr (x:xs) = do putChar x putStr xs IMPERATIVE SHELL
  • 9. Graham Hutton @haskellhutt nextgen :: Board -> Board nextgen b = survivors b ++ births b survivors :: Board -> [Pos] survivors b = [p | p <- b, elem (liveneighbs b p) [2,3]] births :: Board -> [Pos] births b = [p | p <- rmdups (concat (map neighbs b)), isEmpty b p, liveneighbs b p == 3] neighbs :: Pos -> [Pos] neighbs (x,y) = map wrap [(x-1, y-1), (x, y-1), (x+1, y-1), (x-1, y ), (x+1, y), (x-1, y+1), (x, y+1), (x+1, y+1)] wrap :: Pos -> Pos wrap (x,y) = (((x-1) `mod` width) + 1, ((y-1) `mod` height) + 1) width :: Int height :: Int width = 20 height = 20 rmdups :: Eq a => [a] -> [a] rmdups [] = [] rmdups (x:xs) = x : rmdups (filter (/= x) xs) isEmpty :: Board -> Pos -> Bool isEmpty b p = not (isAlive b p) liveneighbs :: Board -> Pos -> Int liveneighbs b = length.filter(isAlive b).neighbs isAlive :: Board -> Pos -> Bool isAlive b p = elem p b pulsar :: Board pulsar = [(4, 2),(5, 2),(6, 2),(10, 2),(11, 2),(12, 2), (2, 4),(7, 4),( 9, 4),(14, 4), (2, 5),(7, 5),( 9, 5),(14, 5), (2, 6),(7, 6),( 9, 6),(14, 6), (4, 7),(5, 7),(6, 7),(10, 7),(11, 7),(12, 7), (4, 9),(5, 9),(6, 9),(10, 9),(11, 9),(12, 9), (2,10),(7,10),( 9,10),(14,10), (2,11),(7,11),( 9,11),(14,11), (2,12),(7,12),( 9,12),(14,12), (4,14),(5,14),(6,14),(10,14),(11,14),(12,14)] type Pos = (Int,Int) type Board = [Pos] FUNCTIONAL CORE
  • 10. User Input I/O part Pure part main cls showcells nextgen life clears screen prints cells to screen wait def nextgen(b:Board):Board FUNCTIONAL CORE IMPERATIVE SHELL goto moves cursor to bottom right def showCells(b: Board): IO[Unit] def cls: IO[Unit] def wait(n:Int): IO[Unit] def life(b: Board): IO[Unit] = cls *> showCells(b) *> goto(width+1,height+1) *> wait(1_000_000) >> life(nextgen(b)) val main: IO[Unit] = life(pulsar) def goto(p: Pos): IO[Unit]
  • 11. val main: IO[Unit] = life(pulsar) def life(b: Board): IO[Unit] = cls *> showCells(b) *> goto(width+1,height+1) *> wait(1_000_000) >> life(nextgen(b)) def cls: IO[Unit] = putStr("u001B[2J") def showCells(b: Board): IO[Unit] = ( for { p <- b } yield writeAt(p, "O") ).sequence_ def wait(n:Int): IO[Unit] = List.fill(n)(IO.unit).sequence_ def writeAt(p: Pos, s: String): IO[Unit] = goto(p) *> putStr(s) def goto(p: Pos): IO[Unit] = p match { case (x,y) => putStr(s"u001B[${y};${x}H") } def putStr(s: String): IO[Unit] = IO { scala.Predef.print(s) } IMPERATIVE SHELL import cats.implicits._, cats.effect.IO main.unsafeRunSync
  • 12. def nextgen(b: Board): Board = survivors(b) ++ births(b) def survivors(b: Board): List[Pos] = for { p <- b if List(2,3) contains liveneighbs(b)(p) } yield p def births(b: Board): List[Pos] = for { p <- rmdups(b flatMap neighbs) if isEmpty(b)(p) if liveneighbs(b)(p) == 3 } yield p def rmdups[A](l: List[A]): List[A] = l match { case Nil => Nil case x::xs => x::rmdups(xs filter(_ != x)) } def isEmpty(b: Board)(p: Pos): Boolean = !(isAlive(b)(p)) def liveneighbs(b: Board)(p: Pos): Int = neighbs(p).filter(isAlive(b)).length def isAlive(b: Board)(p: Pos): Boolean = b contains p def neighbs(p: Pos): List[Pos] = p match { case (x,y) => List( (x - 1, y - 1), (x, y - 1), (x + 1, y - 1), (x - 1, y ), /* cell */ (x + 1, y ), (x - 1, y + 1), (x, y + 1), (x + 1, y + 1) ) map wrap } def wrap(p: Pos): Pos = p match { case (x, y) => (((x - 1) % width) + 1, ((y - 1) % height) + 1) } val width = 20 val height = 20 val pulsar: Board = List( (4, 2),(5, 2),(6, 2),(10, 2),(11, 2),(12, 2), (2, 4),(7, 4),( 9, 4),(14, 4), (2, 5),(7, 5),( 9, 5),(14, 5), (2, 6),(7, 6),( 9, 6),(14, 6), (4, 7),(5, 7),(6, 7),(10, 7),(11, 7),(12, 7), (4, 9),(5, 9),(6, 9),(10, 9),(11, 9),(12, 9), (2,10),(7,10),( 9,10),(14,10), (2,11),(7,11),( 9,11),(14,11), (2,12),(7,12),( 9,12),(14,12), (4,14),(5,14),(6,14),(10,14),(11,14),(12,14)]) FUNCTIONAL CORE type Pos = (Int, Int) type Board = List[Pos]
  • 13. If you want to run the programs, you can find them here: • https://github.com/philipschwarz/functional-core-imperative-shell-scala • https://github.com/philipschwarz/functional-core-imperative-shell-haskell That’s all. I hope you found it useful. See you soon. @philip_schwarz