SlideShare a Scribd company logo
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 (20)

PDF
Sierpinski Triangle - Polyglot FP for Fun and Profit - Haskell and Scala
Philip Schwarz
 
PDF
N-Queens Combinatorial Problem - Polyglot FP for Fun and Profit – Haskell and...
Philip Schwarz
 
PDF
Point free or die - tacit programming in Haskell and beyond
Philip Schwarz
 
PDF
Sequence and Traverse - Part 1
Philip Schwarz
 
PDF
Tagless Final Encoding - Algebras and Interpreters and also Programs
Philip Schwarz
 
PDF
The Functional Programming Triad of Map, Filter and Fold
Philip Schwarz
 
PDF
Functional Domain Modeling - The ZIO 2 Way
Debasish Ghosh
 
PDF
Scala 3 by Example - Algebraic Data Types for Domain Driven Design - Part 1
Philip Schwarz
 
PDF
Domain Modeling in a Functional World
Debasish Ghosh
 
PDF
Functions-Computer programming
nmahi96
 
PDF
The Expression Problem - Part 1
Philip Schwarz
 
PPTX
Writer Monad for logging execution of functions
Philip Schwarz
 
PPT
16 virtual function
Docent Education
 
ZIP
Adapter Design Pattern
guy_davis
 
PDF
Quicksort - a whistle-stop tour of the algorithm in five languages and four p...
Philip Schwarz
 
PDF
Scala 3 by Example - Algebraic Data Types for Domain Driven Design - Part 2
Philip Schwarz
 
PPT
20. Object-Oriented Programming Fundamental Principles
Intro C# Book
 
PDF
Python modules
Learnbay Datascience
 
PDF
3.2 javascript regex
Jalpesh Vasa
 
PDF
Algebraic Data Types for Data Oriented Programming - From Haskell and Scala t...
Philip Schwarz
 
Sierpinski Triangle - Polyglot FP for Fun and Profit - Haskell and Scala
Philip Schwarz
 
N-Queens Combinatorial Problem - Polyglot FP for Fun and Profit – Haskell and...
Philip Schwarz
 
Point free or die - tacit programming in Haskell and beyond
Philip Schwarz
 
Sequence and Traverse - Part 1
Philip Schwarz
 
Tagless Final Encoding - Algebras and Interpreters and also Programs
Philip Schwarz
 
The Functional Programming Triad of Map, Filter and Fold
Philip Schwarz
 
Functional Domain Modeling - The ZIO 2 Way
Debasish Ghosh
 
Scala 3 by Example - Algebraic Data Types for Domain Driven Design - Part 1
Philip Schwarz
 
Domain Modeling in a Functional World
Debasish Ghosh
 
Functions-Computer programming
nmahi96
 
The Expression Problem - Part 1
Philip Schwarz
 
Writer Monad for logging execution of functions
Philip Schwarz
 
16 virtual function
Docent Education
 
Adapter Design Pattern
guy_davis
 
Quicksort - a whistle-stop tour of the algorithm in five languages and four p...
Philip Schwarz
 
Scala 3 by Example - Algebraic Data Types for Domain Driven Design - Part 2
Philip Schwarz
 
20. Object-Oriented Programming Fundamental Principles
Intro C# Book
 
Python modules
Learnbay Datascience
 
3.2 javascript regex
Jalpesh Vasa
 
Algebraic Data Types for Data Oriented Programming - From Haskell and Scala t...
Philip Schwarz
 

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

PDF
## Part B- Conway's Game of Life ### Introduction John Conway's Ga.pdf
BANSALANKIT1077
 
PPTX
А нам-то зачем функциональное программирование?
Vagif Abilov
 
PPTX
абилов а зачем нам функциональное программирование
Magneta AI
 
PDF
Scala Functional Patterns
league
 
PDF
QuickCheck - Software Testing
Javran
 
PPTX
Solving Haskell Assignment: Engaging Challenges and Solutions for University ...
Programming Homework Help
 
PDF
Game of Life - Polyglot FP - Haskell, Scala, Unison - Part 2 - with minor cor...
Philip Schwarz
 
PDF
Haskell for data science
John Cant
 
PPTX
Purely Functional Data Structures in Scala
Vladimir Kostyukov
 
PPT
Chap12alg
Munkhchimeg
 
PPT
Chap12alg
Munhchimeg
 
PPTX
Advanced data structure
Shakil Ahmed
 
PDF
Fun never stops. introduction to haskell programming language
Pawel Szulc
 
PDF
Why Haskell Matters
romanandreg
 
PDF
Functional programming-advantages
Sergei Winitzki
 
PPTX
Introduction to Haskell: 2011-04-13
Jay Coskey
 
PDF
01. haskell introduction
Sebastian Rettig
 
PDF
Introduction to Functional Languages
suthi
 
PDF
The Fuss about || Haskell | Scala | F# ||
Ashwin Rao
 
PDF
高いChurn耐性と検索性能を持つキー順序保存型構造化オーバレイネットワークSuzakuの提案と評価
Kota Abe
 
## Part B- Conway's Game of Life ### Introduction John Conway's Ga.pdf
BANSALANKIT1077
 
А нам-то зачем функциональное программирование?
Vagif Abilov
 
абилов а зачем нам функциональное программирование
Magneta AI
 
Scala Functional Patterns
league
 
QuickCheck - Software Testing
Javran
 
Solving Haskell Assignment: Engaging Challenges and Solutions for University ...
Programming Homework Help
 
Game of Life - Polyglot FP - Haskell, Scala, Unison - Part 2 - with minor cor...
Philip Schwarz
 
Haskell for data science
John Cant
 
Purely Functional Data Structures in Scala
Vladimir Kostyukov
 
Chap12alg
Munkhchimeg
 
Chap12alg
Munhchimeg
 
Advanced data structure
Shakil Ahmed
 
Fun never stops. introduction to haskell programming language
Pawel Szulc
 
Why Haskell Matters
romanandreg
 
Functional programming-advantages
Sergei Winitzki
 
Introduction to Haskell: 2011-04-13
Jay Coskey
 
01. haskell introduction
Sebastian Rettig
 
Introduction to Functional Languages
suthi
 
The Fuss about || Haskell | Scala | F# ||
Ashwin Rao
 
高いChurn耐性と検索性能を持つキー順序保存型構造化オーバレイネットワークSuzakuの提案と評価
Kota Abe
 
Ad

More from Philip Schwarz (20)

PDF
Folding Cheat Sheet Series Titles - a series of 9 decks
Philip Schwarz
 
PDF
Folding Cheat Sheet # 9 - List Unfolding 𝑢𝑛𝑓𝑜𝑙𝑑 as the Computational Dual of ...
Philip Schwarz
 
PDF
List Unfolding - 'unfold' as the Computational Dual of 'fold', and how 'unfol...
Philip Schwarz
 
PDF
Drawing Heighway’s Dragon - Part 4 - Interactive and Animated Dragon Creation
Philip Schwarz
 
PDF
The Nature of Complexity in John Ousterhout’s Philosophy of Software Design
Philip Schwarz
 
PDF
Drawing Heighway’s Dragon - Part 3 - Simplification Through Separation of Con...
Philip Schwarz
 
PDF
The Open-Closed Principle - Part 2 - The Contemporary Version - An Introduction
Philip Schwarz
 
PDF
The Open-Closed Principle - Part 1 - The Original Version
Philip Schwarz
 
PDF
Drawing Heighway’s Dragon - Part II - Recursive Function Simplification - Fro...
Philip Schwarz
 
PDF
Drawing Heighway’s Dragon - Recursive Function Rewrite - From Imperative Styl...
Philip Schwarz
 
PDF
Fibonacci Function Gallery - Part 2 - One in a series
Philip Schwarz
 
PDF
Fibonacci Function Gallery - Part 1 (of a series) - with minor corrections
Philip Schwarz
 
PDF
Fibonacci Function Gallery - Part 1 (of a series)
Philip Schwarz
 
PDF
The Debt Metaphor - Ward Cunningham in his 2009 YouTube video
Philip Schwarz
 
PDF
Folding Cheat Sheet Series Titles (so far)
Philip Schwarz
 
PDF
From Subtype Polymorphism To Typeclass-based Ad hoc Polymorphism - An Example
Philip Schwarz
 
PDF
Folding Cheat Sheet #8 - eighth in a series
Philip Schwarz
 
PDF
Function Applicative for Great Good of Leap Year Function
Philip Schwarz
 
PDF
Folding Cheat Sheet #7 - seventh in a series
Philip Schwarz
 
PDF
Folding Cheat Sheet #6 - sixth in a series
Philip Schwarz
 
Folding Cheat Sheet Series Titles - a series of 9 decks
Philip Schwarz
 
Folding Cheat Sheet # 9 - List Unfolding 𝑢𝑛𝑓𝑜𝑙𝑑 as the Computational Dual of ...
Philip Schwarz
 
List Unfolding - 'unfold' as the Computational Dual of 'fold', and how 'unfol...
Philip Schwarz
 
Drawing Heighway’s Dragon - Part 4 - Interactive and Animated Dragon Creation
Philip Schwarz
 
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...
Philip Schwarz
 
The Open-Closed Principle - Part 2 - The Contemporary Version - An Introduction
Philip Schwarz
 
The Open-Closed Principle - Part 1 - The Original Version
Philip Schwarz
 
Drawing Heighway’s Dragon - Part II - Recursive Function Simplification - Fro...
Philip Schwarz
 
Drawing Heighway’s Dragon - Recursive Function Rewrite - From Imperative Styl...
Philip Schwarz
 
Fibonacci Function Gallery - Part 2 - One in a series
Philip Schwarz
 
Fibonacci Function Gallery - Part 1 (of a series) - with minor corrections
Philip Schwarz
 
Fibonacci Function Gallery - Part 1 (of a series)
Philip Schwarz
 
The Debt Metaphor - Ward Cunningham in his 2009 YouTube video
Philip Schwarz
 
Folding Cheat Sheet Series Titles (so far)
Philip Schwarz
 
From Subtype Polymorphism To Typeclass-based Ad hoc Polymorphism - An Example
Philip Schwarz
 
Folding Cheat Sheet #8 - eighth in a series
Philip Schwarz
 
Function Applicative for Great Good of Leap Year Function
Philip Schwarz
 
Folding Cheat Sheet #7 - seventh in a series
Philip Schwarz
 
Folding Cheat Sheet #6 - sixth in a series
Philip Schwarz
 
Ad

Recently uploaded (20)

PDF
SAP Firmaya İade ABAB Kodları - ABAB ile yazılmıl hazır kod örneği
Salih Küçük
 
PDF
Thread In Android-Mastering Concurrency for Responsive Apps.pdf
Nabin Dhakal
 
PDF
Revenue streams of the Wazirx clone script.pdf
aaronjeffray
 
PPTX
Coefficient of Variance in IBM SPSS Statistics Version 31.pptx
Version 1 Analytics
 
PPTX
Java Native Memory Leaks: The Hidden Villain Behind JVM Performance Issues
Tier1 app
 
PDF
Unlock Efficiency with Insurance Policy Administration Systems
Insurance Tech Services
 
PDF
GetOnCRM Speeds Up Agentforce 3 Deployment for Enterprise AI Wins.pdf
GetOnCRM Solutions
 
PPTX
Why Businesses Are Switching to Open Source Alternatives to Crystal Reports.pptx
Varsha Nayak
 
PPTX
Writing Better Code - Helping Developers make Decisions.pptx
Lorraine Steyn
 
PPTX
ChiSquare Procedure in IBM SPSS Statistics Version 31.pptx
Version 1 Analytics
 
PDF
iTop VPN With Crack Lifetime Activation Key-CODE
utfefguu
 
PPTX
In From the Cold: Open Source as Part of Mainstream Software Asset Management
Shane Coughlan
 
PDF
SciPy 2025 - Packaging a Scientific Python Project
Henry Schreiner
 
PPTX
Agentic Automation Journey Session 1/5: Context Grounding and Autopilot for E...
klpathrudu
 
PDF
Linux Certificate of Completion - LabEx Certificate
VICTOR MAESTRE RAMIREZ
 
PPTX
Agentic Automation Journey Series Day 2 – Prompt Engineering for UiPath Agents
klpathrudu
 
PPTX
Hardware(Central Processing Unit ) CU and ALU
RizwanaKalsoom2
 
PPTX
Tally_Basic_Operations_Presentation.pptx
AditiBansal54083
 
PDF
HiHelloHR – Simplify HR Operations for Modern Workplaces
HiHelloHR
 
PDF
Open Chain Q2 Steering Committee Meeting - 2025-06-25
Shane Coughlan
 
SAP Firmaya İade ABAB Kodları - ABAB ile yazılmıl hazır kod örneği
Salih Küçük
 
Thread In Android-Mastering Concurrency for Responsive Apps.pdf
Nabin Dhakal
 
Revenue streams of the Wazirx clone script.pdf
aaronjeffray
 
Coefficient of Variance in IBM SPSS Statistics Version 31.pptx
Version 1 Analytics
 
Java Native Memory Leaks: The Hidden Villain Behind JVM Performance Issues
Tier1 app
 
Unlock Efficiency with Insurance Policy Administration Systems
Insurance Tech Services
 
GetOnCRM Speeds Up Agentforce 3 Deployment for Enterprise AI Wins.pdf
GetOnCRM Solutions
 
Why Businesses Are Switching to Open Source Alternatives to Crystal Reports.pptx
Varsha Nayak
 
Writing Better Code - Helping Developers make Decisions.pptx
Lorraine Steyn
 
ChiSquare Procedure in IBM SPSS Statistics Version 31.pptx
Version 1 Analytics
 
iTop VPN With Crack Lifetime Activation Key-CODE
utfefguu
 
In From the Cold: Open Source as Part of Mainstream Software Asset Management
Shane Coughlan
 
SciPy 2025 - Packaging a Scientific Python Project
Henry Schreiner
 
Agentic Automation Journey Session 1/5: Context Grounding and Autopilot for E...
klpathrudu
 
Linux Certificate of Completion - LabEx Certificate
VICTOR MAESTRE RAMIREZ
 
Agentic Automation Journey Series Day 2 – Prompt Engineering for UiPath Agents
klpathrudu
 
Hardware(Central Processing Unit ) CU and ALU
RizwanaKalsoom2
 
Tally_Basic_Operations_Presentation.pptx
AditiBansal54083
 
HiHelloHR – Simplify HR Operations for Modern Workplaces
HiHelloHR
 
Open Chain Q2 Steering Committee Meeting - 2025-06-25
Shane Coughlan
 

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