Transition graph using free monads and existentials

Alexander Granin
Alexander GraninSoftware Developer, Independent Consultant at Independent Consultant
Alexander Granin
graninas@gmail.com
eDSL for transition graph using Free
monads and existential types
Transition graph using free monads and existentials
Structure
● The problem
● Embedded DSLs design
● Transition Graph eDSL
● Sample application
● Implementation
● Why you shouldn’t write such code
data FlowMethodF a s
= RunUI (Interaction (UIResult s)) (UIResult s -> a)
| ForkUI (Interaction (UIResult s)) a
| CallAPI (Interaction (APIResult s)) (APIResult s -> a)
| Get Store Key (Maybe String -> a)
| Set Store Key String a
| Fork (Flow s) (Control s -> a)
| DoAff (forall eff. AppFlow eff s) (s -> a)
| Await (Control s) (s -> a)
| Delay Milliseconds a
| OneOf (Array (Flow s)) (s -> a)
| HandleError (Flow (ErrorHandler s)) (s -> a)
| CheckPermissions (Array Permission) (PermissionStatus -> a)
| TakePermissions (Array Permission) (Array PermissionResponse -> a)
Presto
Framework
https://github.com/juspay/purescript-presto
The problem
Presto: flows
billPayFlow :: MobileNumber -> ScreenFlow
billPayFlow number = do
amount <- UI.askAmount
result <- Remote.payBill number amount
billPayStatus number amount result
billPayStatus :: MobileNumber -> Amount -> BillPayStatus -> ScreenFlow
billPayStatus number amount status = do
action <- runUI' (StatusScreen number amount status)
case action of
SuccessResult -> pure SuccessResult
StatusScreenAbort -> billPayFlow number -- recursion
BackT (MFlow)
main = runBackT $ do
lift $ log "Starting Run"
a <- backPoint (randomInt 1 10) -- point to return
lift $ log "A number"
unless (a >= 9) $ BackT (pure GoBack) -- return from here
b <- backPoint (randomInt 1 10) -- point to return
lift $ log "Another number"
unless (b >= 9) $ BackT (pure GoBack) -- return from here
lift $ logShow (a + b)
https://hackage.haskell.org/package/MFlow
BackT + flows: how it could possibly look
billPayFlow :: MobileNumber -> BackTScreenFlow
billPayFlow number = do
amount <- backPoint UI.askAmount -- point to return
result <- lift $ Remote.payBill number amount
billPayStatus number amount result
billPayStatus :: MobileNumber -> Amount -> BillPayStatus -> BackTScreenFlow
billPayStatus number amount status = do
action <- lift $ runUI' (StatusScreen number amount status)
case action of
SuccessResult -> pure SuccessResult
StatusScreenAbort -> BackT (pure GoBack) -- go back from here
BackT: not a monad, actually
-- https://gist.github.com/ninegua/97833cb4f82451f6c3db
-- Unfortunately, BackT is not a monad. It violates the associative
-- law, as the program shown below, test1 enters an infinite loop,
-- and test2 exits after printing 3 lines.
test1 = runBackT (a >> (b >> c))
test2 = runBackT ((a >> b) >> c)
a = lift (print "step 1") >> breturn ()
b = lift (print "step 2") >> return ()
c = lift (print "step 3") >> fail ""
Embedded DSLs design
1. Make it look good
3 steps of eDSL design
1. Make it look good
2. Make it compile
3 steps of eDSL design
1. Make it look good
2. Make it compile
3. Make it work
3 steps of eDSL design
detailsFlowTrans =
trans detailsFlow
</> [ onCalculate (trans calculateFlow) ]
/> [ onClose (trans submitFlow ) ]
detailsFlow :: Flow Int
detailsFlow = pure 10
calculateFlow :: Int -> Flow Unit
calculateFlow _ = pure unit
submitFlow :: Int -> Flow Unit
submitFlow _ = pure unit
Inventing eDSL syntax, try #1
homeFlowTrans =
trans homeFlow
<~> onClose (trans closeFlow)
operationsFlowTrans =
trans transactionFlow
<~> onDetails (trans detailsFlow )
<~> onSettings (trans settingsFlow)
~> onHome homeFlowTrans
Inventing eDSL syntax, try #2
operationsFlowTrans = do
t <- with transactionFlow
backableTrans t onDetails (trans detailsFlow )
backableTrans t onSettings (trans settingsFlow)
forwardOnlyTrans t onHome (trans homeFlow )
Maybe, monads?
operationsFlowTrans =
(forwardOnly
(backable
(backable
(trans transactionFlow)
(onDetails (trans detailsFlow))
)
(onSettings (trans settingsFlow))
)
(onHome (trans homeFlow))
)
Less is more. No syntax, please
detailsFlowGraph :: Graph Unit Unit
detailsFlowGraph = graph $
with detailsFlow
<~> on "calculate" (leaf1 calculateFlow)
~> on "enter" (leaf1 submitFlow )
Final version of eDSL
Transition Graph eDSL
node1 :: Graph IO () ()
node1 = graph $
with (print "node1" >> getInput)
<~> on "go 3" node3
~> on "go 2" node2
/> node1
node2 :: Graph IO () ()
node2 = graph $
with (print "node2" >> nop)
-/> node3
node3 :: Graph IO () ()
node3 = graph $
with (print "node3" >> getInput)
</> node1
~> on "exit" (leaf nop)
getInput :: IO (Event, ())
getInput = do
input <- getLine
pure (input, ())
nop :: IO (Event, ())
nop = pure ("", ())
main = runGraph' id (== "back") node1
Sample: Graph + IO
node1 :: Graph IO () Int
node1 = graph $
with (pure ("", 100500))
-/> node2
node2 :: Graph IO Int ()
node2 = graph $
with1 (n -> print n >> getInput)
<~> on "go 3" node3
/> node1
node3 :: Graph IO () ()
node3 = graph $
with (print "bye")
-/> (leaf nop)
getInput :: IO (Event, ())
getInput = do
input <- getLine
pure (input, ())
nop :: IO (Event, ())
nop = pure ("", ())
main = runGraph' id (== "back") node1
Typing
(~>) By event, forward-only
(<~>) By event, backable (uses a specified event to allow back transition)
(>~<) By event, go forward and return unconditionally
(/>) Default, forward-only
(</>) Default, backable
(-/>) Default, pass through node unconditionally (overrides other transitions)
Transitions
(~>) By event, forward-only
(<~>) By event, backable (uses a specified event to allow back transition)
(>~<) By event, go forward and return unconditionally
(/>) Default, forward-only
(</>) Default, backable
(-/>) Default, pass through node unconditionally (overrides other transitions)
Planned:
(?/>) Default, with a given condition
(!/>) Default, random with a given chance
(!~>) By event, random with a given chance
(?~>) By event, with a given condition
(!?~>) By event, with a given condition, random with a given chance
Transitions
Sample application
Game eDSL
data AdventureLF next where
GetUserInput :: (String -> next) -> AdventureLF next
PrintMessage :: String -> next -> AdventureLF next
GetObj :: FromJSON a => String -> (a -> next) -> AdventureLF next
type AdventureL = Free AdventureLF
Game eDSL
data AdventureLF next where
GetUserInput :: (String -> next) -> AdventureLF next
PrintMessage :: String -> next -> AdventureLF next
GetObj :: FromJSON a => String -> (a -> next) -> AdventureLF next
type AdventureL = Free AdventureLF
westOfHouse' :: (Bool, Bool) -> AdventureL ()
westOfHouse' (showDescr, showMailbox) = do
mailbox :: Mailbox <- getObject "mailbox"
printMessage "West of House"
when showDescr $ printMessage "This is an open field west of a white house."
when showMailbox $ printMessage $ describeObject mailbox
type AGGraph a b = Graph AdventureL a b
game :: AGGraph () ()
game = graph $
with (inputOnly (True, True))
-/> westOfHouse
westOfHouse :: AGGraph (Bool, Bool) ()
westOfHouse = graph $
with1 (x -> westOfHouse' x >> getInput)
~> on "open mailbox" (openMailbox (False, False))
/> leaf nop
openMailbox :: (Bool, Bool) -> AGGraph () ()
openMailbox houseView = graph $
with (evalAction MailboxType "open" "mailbox" >> inputOnly houseView)
-/> westOfHouse
Game transition graph
Game output
West of House
This is an open field west of a white house, with a boarded front door.
This is a small mailbox.
A rubber mat saying 'Welcome to Zork!' lies by the door.
> open mailbox
Opening mailbox revealed leaflet
> open mailbox
Mailbox already opened.
Implementation
newtype Graph lang i o
= Graph (Exists (GraphF lang i o))
data GraphF lang i o b
= GraphF1 (i -> lang (Event, b)) (Transitions lang b o ())
data Exists f where
Exists :: f a -> Exists f
Graph: existential data type
Graph lang i o
Exists (GraphF lang i o)
Graph lang i o
Exists (GraphF lang i o)
GraphF lang i o b
Graph lang i o
Exists (GraphF lang i o)
GraphF lang i o b
GraphF1 (i -> lang (Event, b))
(Transitions lang b o ())
Graph lang i o
Exists (GraphF lang i o)
GraphF lang i o b
GraphF1 (i -> lang (Event, b))
(Transitions lang b o ())
Transition (Graph lang b o)
Exists (GraphF lang b o)
Graph lang i o
Exists (GraphF lang i o)
GraphF lang i o b
GraphF1 (i -> lang (Event, b))
(Transitions lang b o ())
Transition (Graph lang b o)
Exists (GraphF lang b o)
GraphF lang b o b2
Graph lang i o
Exists (GraphF lang i o)
GraphF lang i o b
GraphF1 (i -> lang (Event, b))
(Transitions lang b o ())
Transition (Graph lang b o)
Exists (GraphF lang b o)
GraphF lang b o b2
GraphF1 (b -> lang (Event, b2))
(Transitions lang b2 o ())
module Data.Exists where
import Unsafe.Coerce (unsafeCoerce)
data Exists f where
Exists :: f a -> Exists f
mkExists :: forall f a. f a -> Exists f
mkExists = unsafeCoerce
runExists :: forall f r. (forall a. f a -> r) -> (Exists f -> r)
runExists = unsafeCoerce
Exists: hacky data type
with1
:: (Monad lang)
=> (i -> lang (Event, b))
-> Transitions lang b o ()
-> Graph lang i o
with1 langF1 table = Graph $ mkExists $ GraphF1 langF1 table
case matchTransition event prevGraph of
PassThrough (Graph graphEx) -> runExists (runTransition input) graphEx
Construction and deconstruction of existential type
with1
:: (Monad lang)
=> (i -> lang (Event, b))
-> Transitions lang b o ()
-> Graph lang i o
node0 = graph $
with something
<~> on "event 1" node1
~> on "event 2" node2
>~< on "event 3" node3
</> node4
/> node5
Transitions data type
type Transitions lang b o u = Free (TransitionF lang b o) u
data TransitionF lang b o next
= Transition Event (TransitionDef (Graph lang b o)) next
| PassThroughTransition (Graph lang b o) next
| PassDefaultForwardOnlyTransition (Graph lang b o) next
| PassDefaultBackableTransition (Graph lang b o) next
data TransitionDef graph
= Backable graph
| ForwardOnly graph
| AutoBack graph
| PassThrough graph
| PassDefaultForwardOnly graph
| PassDefaultBackable graph
| NoTransition
Transitions: Free monad data type
interpret
:: Event
-> TransitionF lang b o u
-> Interpreter (Graph lang b o) u
interpret currentEvent (PassThroughTransition g next) = do
transDef' <- get
case transDef' of
PassThrough _ -> pure next
_ -> put (PassThrough g) >> pure next
interpret currentEvent (PassDefaultBackableTransition g next) = do
transDef' <- get
case transDef' of
NoTransition -> put (PassDefaultBackable g) >> pure next
_ -> pure next
Transitions interpreter
(-/>)
(</>)
Running graph
Running graph
runTransition'
:: (Monad m, Monad lang)
=> Runtime lang m
-> ThisBackable
-> AutoReturn
-> i
-> GraphF lang i o b
-> m TransitionResult
runTransition' runtime backable autoReturn i3 g3 = do
let f3 = getLang i3 g3
transitionResult <- runTransition runtime autoReturn f3 g3
case transitionResult of
Done
-> pure Done
AutoFallbackRerun -> pure FallbackRerun
FallbackRerun
-> runTransition' runtime backable thisNotAutoReturn i3 g3
Fallback
->
if isBackable backable
then pure FallbackRerun
else pure Done -- throw "No fallback"
GoForward e2 i3 -> case matchTransition e2 g2 of
NoTransition
-> pure Done
PassThrough g3@(Graph g3Ex) ->
runExists (runTransition' runtime thisNotBackable thisNotAutoReturn i3) g3Ex
PassDefaultForwardOnly g3@(Graph g3Ex) ->
runExists (runTransition' runtime thisNotBackable thisNotAutoReturn i3) g3Ex
PassDefaultBackable g3@(Graph g3Ex) ->
runExists (runTransition' runtime thisBackable
thisNotAutoReturn i3) g3Ex
Backable
g3@(Graph g3Ex) ->
runExists (runTransition' runtime thisBackable
thisNotAutoReturn i3)
ForwardOnly g3@(Graph g3Ex) ->
runExists (runTransition' runtime thisNotBacka
AutoBack
g3@(Graph g3Ex) ->
runExists (runTransit
runLang
:: (Monad m, Monad lang)
=> Runtime lang m
-> lang (LangOutput a)
-> m (LangResult Event a)
runLang (Runtime runLang isBackEvent)
lang = do(e, i) <- runLang lang
if isBackEvent e
then pure GoBackward
else pure $ GoForward e i
data Runtime lang m = Runtime
{ runLang_ :: Runner
lang m
, isBackEvent_ :: Event ->
Bool
}
data LangResult a b =
GoForward a b | GoBackward
data TransitionResult
= Fallback
| AutoFallbackRerun
| FallbackRerun
| Done
Why you shouldn’t write such code
● Exists is hack Use GADTs
Why you shouldn’t write such code
● Exists is hack Use GADTs
● Overengineering Kmettism is out there
Why you shouldn’t write such code
● Exists is hack Use GADTs
● Overengineering Kmettism is out there
● Overengineering - 2 Free monad can be replaced by Map or list
Why you shouldn’t write such code
● Exists is hack Use GADTs
● Overengineering Kmettism is out there
● Overengineering - 2 Free monad can be replaced by Map
● Don't reinvent the wheel Use generic libraries for graphs
Why you shouldn’t write such code
● Exists is hack Use GADTs
● Overengineering Kmettism is out there
● Overengineering - 2 Free monad can be replaced by Map
● Don't reinvent the wheel Use generic libraries for graphs
● Don't reinvent the wheel - 2 You probably need FRP
Why you shouldn’t write such code
● Exists is hack Use GADTs
● Overengineering Kmettism is out there
● Overengineering - 2 Free monad can be replaced by Map
● Don't reinvent the wheel Use generic libraries for graphs
● Don't reinvent the wheel - 2 You probably need FRP
● Don't reinvent the wheel - 3 Is Graph In Out type just the Arrow In Out type?
Why you shouldn’t write such code
● Exists is hack Use GADTs
● Overengineering Kmettism is out there
● Overengineering - 2 Free monad can be replaced by Map
● Don't reinvent the wheel Use generic libraries for graphs
● Don't reinvent the wheel - 2 You probably need FRP
● Don't reinvent the wheel - 3 Is Graph In Out type just the Arrow In Out type?
● Don’t reinvent the wheel - 4 It’s just a State Machine, isn’t it?
Everyone knows that debugging is twice as hard as
writing a program in the first place. So if you're as
clever as you can be when you write it, how will you
ever debug it?
Brian Kernighan
Alexander Granin
graninas@gmail.com
Thanks for watching!
1 of 51

Recommended

81818088 isc-class-xii-computer-science-project-java-programs by
81818088 isc-class-xii-computer-science-project-java-programs81818088 isc-class-xii-computer-science-project-java-programs
81818088 isc-class-xii-computer-science-project-java-programsAbhishek Jena
13.6K views77 slides
C# console programms by
C# console programmsC# console programms
C# console programmsYasir Khan
10.4K views12 slides
Pattern printing programs by
Pattern printing programsPattern printing programs
Pattern printing programsMukesh Tekwani
13.4K views8 slides
Isc computer project final upload last by
Isc computer project final upload lastIsc computer project final upload last
Isc computer project final upload lastArunav Ray
28.8K views81 slides
서버 개발자가 바라 본 Functional Reactive Programming with RxJava - SpringCamp2015 by
서버 개발자가 바라 본 Functional Reactive Programming with RxJava - SpringCamp2015서버 개발자가 바라 본 Functional Reactive Programming with RxJava - SpringCamp2015
서버 개발자가 바라 본 Functional Reactive Programming with RxJava - SpringCamp2015NAVER / MusicPlatform
38.4K views54 slides
Halogen: Past, Present, and Future by
Halogen: Past, Present, and FutureHalogen: Past, Present, and Future
Halogen: Past, Present, and FutureJohn De Goes
2.9K views31 slides

More Related Content

What's hot

Lambda Expressions in C++ by
Lambda Expressions in C++Lambda Expressions in C++
Lambda Expressions in C++Patrick Viafore
610 views19 slides
Embedding Generic Monadic Transformer into Scala. [Tfp2022] by
Embedding Generic Monadic Transformer into Scala. [Tfp2022]Embedding Generic Monadic Transformer into Scala. [Tfp2022]
Embedding Generic Monadic Transformer into Scala. [Tfp2022]Ruslan Shevchenko
289 views28 slides
Java/Scala Lab: Анатолий Кметюк - Scala SubScript: Алгебра для реактивного пр... by
Java/Scala Lab: Анатолий Кметюк - Scala SubScript: Алгебра для реактивного пр...Java/Scala Lab: Анатолий Кметюк - Scala SubScript: Алгебра для реактивного пр...
Java/Scala Lab: Анатолий Кметюк - Scala SubScript: Алгебра для реактивного пр...GeeksLab Odessa
683 views33 slides
The Design of the Scalaz 8 Effect System by
The Design of the Scalaz 8 Effect SystemThe Design of the Scalaz 8 Effect System
The Design of the Scalaz 8 Effect SystemJohn De Goes
5.5K views68 slides
jq: JSON - Like a Boss by
jq: JSON - Like a Bossjq: JSON - Like a Boss
jq: JSON - Like a BossBob Tiernay
12.7K views63 slides
C# by
C#C#
C#actacademy
2.6K views44 slides

What's hot(16)

Embedding Generic Monadic Transformer into Scala. [Tfp2022] by Ruslan Shevchenko
Embedding Generic Monadic Transformer into Scala. [Tfp2022]Embedding Generic Monadic Transformer into Scala. [Tfp2022]
Embedding Generic Monadic Transformer into Scala. [Tfp2022]
Ruslan Shevchenko289 views
Java/Scala Lab: Анатолий Кметюк - Scala SubScript: Алгебра для реактивного пр... by GeeksLab Odessa
Java/Scala Lab: Анатолий Кметюк - Scala SubScript: Алгебра для реактивного пр...Java/Scala Lab: Анатолий Кметюк - Scala SubScript: Алгебра для реактивного пр...
Java/Scala Lab: Анатолий Кметюк - Scala SubScript: Алгебра для реактивного пр...
GeeksLab Odessa683 views
The Design of the Scalaz 8 Effect System by John De Goes
The Design of the Scalaz 8 Effect SystemThe Design of the Scalaz 8 Effect System
The Design of the Scalaz 8 Effect System
John De Goes5.5K views
jq: JSON - Like a Boss by Bob Tiernay
jq: JSON - Like a Bossjq: JSON - Like a Boss
jq: JSON - Like a Boss
Bob Tiernay12.7K views
Scalaz By Example (An IO Taster) -- PDXScala Meetup Jan 2014 by Susan Potter
Scalaz By Example (An IO Taster) -- PDXScala Meetup Jan 2014Scalaz By Example (An IO Taster) -- PDXScala Meetup Jan 2014
Scalaz By Example (An IO Taster) -- PDXScala Meetup Jan 2014
Susan Potter2.9K views
A "Do-It-Yourself" Specification Language with BeepBeep 3 (Talk @ Dagstuhl 2017) by Sylvain Hallé
A "Do-It-Yourself" Specification Language with BeepBeep 3 (Talk @ Dagstuhl 2017)A "Do-It-Yourself" Specification Language with BeepBeep 3 (Talk @ Dagstuhl 2017)
A "Do-It-Yourself" Specification Language with BeepBeep 3 (Talk @ Dagstuhl 2017)
Sylvain Hallé176 views
stack by eShikshak
stackstack
stack
eShikshak4.2K views
High performance web programming with C++14 by Matthieu Garrigues
High performance web programming with C++14High performance web programming with C++14
High performance web programming with C++14
Matthieu Garrigues3.5K views
The Ring programming language version 1.3 book - Part 25 of 88 by Mahmoud Samir Fayed
The Ring programming language version 1.3 book - Part 25 of 88The Ring programming language version 1.3 book - Part 25 of 88
The Ring programming language version 1.3 book - Part 25 of 88
scala-gopher: async implementation of CSP for scala by Ruslan Shevchenko
scala-gopher:  async implementation of CSP  for  scalascala-gopher:  async implementation of CSP  for  scala
scala-gopher: async implementation of CSP for scala
Ruslan Shevchenko1.9K views

Similar to Transition graph using free monads and existentials

Refactoring to Macros with Clojure by
Refactoring to Macros with ClojureRefactoring to Macros with Clojure
Refactoring to Macros with ClojureDmitry Buzdin
3.5K views51 slides
Big Data Day LA 2016/ Hadoop/ Spark/ Kafka track - Iterative Spark Developmen... by
Big Data Day LA 2016/ Hadoop/ Spark/ Kafka track - Iterative Spark Developmen...Big Data Day LA 2016/ Hadoop/ Spark/ Kafka track - Iterative Spark Developmen...
Big Data Day LA 2016/ Hadoop/ Spark/ Kafka track - Iterative Spark Developmen...Data Con LA
457 views28 slides
The what over the how (another way on android development with kotlin) by
The what over the how (another way on android development with kotlin)The what over the how (another way on android development with kotlin)
The what over the how (another way on android development with kotlin)Jose Manuel Pereira Garcia
1.4K views38 slides
ClojureScript loves React, DomCode May 26 2015 by
ClojureScript loves React, DomCode May 26 2015ClojureScript loves React, DomCode May 26 2015
ClojureScript loves React, DomCode May 26 2015Michiel Borkent
411 views52 slides
Monadologie by
MonadologieMonadologie
Monadologieleague
3.6K views58 slides
Lego: A brick system build by scala by
Lego: A brick system build by scalaLego: A brick system build by scala
Lego: A brick system build by scalalunfu zhong
1.2K views54 slides

Similar to Transition graph using free monads and existentials(20)

Refactoring to Macros with Clojure by Dmitry Buzdin
Refactoring to Macros with ClojureRefactoring to Macros with Clojure
Refactoring to Macros with Clojure
Dmitry Buzdin3.5K views
Big Data Day LA 2016/ Hadoop/ Spark/ Kafka track - Iterative Spark Developmen... by Data Con LA
Big Data Day LA 2016/ Hadoop/ Spark/ Kafka track - Iterative Spark Developmen...Big Data Day LA 2016/ Hadoop/ Spark/ Kafka track - Iterative Spark Developmen...
Big Data Day LA 2016/ Hadoop/ Spark/ Kafka track - Iterative Spark Developmen...
Data Con LA457 views
ClojureScript loves React, DomCode May 26 2015 by Michiel Borkent
ClojureScript loves React, DomCode May 26 2015ClojureScript loves React, DomCode May 26 2015
ClojureScript loves React, DomCode May 26 2015
Michiel Borkent411 views
Monadologie by league
MonadologieMonadologie
Monadologie
league3.6K views
Lego: A brick system build by scala by lunfu zhong
Lego: A brick system build by scalaLego: A brick system build by scala
Lego: A brick system build by scala
lunfu zhong1.2K views
[FT-11][suhorng] “Poor Man's” Undergraduate Compilers by Functional Thursday
[FT-11][suhorng] “Poor Man's” Undergraduate Compilers[FT-11][suhorng] “Poor Man's” Undergraduate Compilers
[FT-11][suhorng] “Poor Man's” Undergraduate Compilers
Столпы функционального программирования для адептов ООП, Николай Мозговой by Sigma Software
Столпы функционального программирования для адептов ООП, Николай МозговойСтолпы функционального программирования для адептов ООП, Николай Мозговой
Столпы функционального программирования для адептов ООП, Николай Мозговой
Sigma Software128 views
オープンデータを使ったモバイルアプリ開発(応用編) by Takayuki Goto
オープンデータを使ったモバイルアプリ開発(応用編)オープンデータを使ったモバイルアプリ開発(応用編)
オープンデータを使ったモバイルアプリ開発(応用編)
Takayuki Goto142 views
Stephan Ewen - Scaling to large State by Flink Forward
Stephan Ewen - Scaling to large StateStephan Ewen - Scaling to large State
Stephan Ewen - Scaling to large State
Flink Forward2.6K views
Reactive Programming Patterns with RxSwift by Florent Pillet
Reactive Programming Patterns with RxSwiftReactive Programming Patterns with RxSwift
Reactive Programming Patterns with RxSwift
Florent Pillet3.6K views
Asynchronous programming done right - Node.js by Piotr Pelczar
Asynchronous programming done right - Node.jsAsynchronous programming done right - Node.js
Asynchronous programming done right - Node.js
Piotr Pelczar6.9K views
Scala-Gopher: CSP-style programming techniques with idiomatic Scala. by Ruslan Shevchenko
Scala-Gopher: CSP-style programming techniques with idiomatic Scala.Scala-Gopher: CSP-style programming techniques with idiomatic Scala.
Scala-Gopher: CSP-style programming techniques with idiomatic Scala.
Ruslan Shevchenko698 views
Pick up the low-hanging concurrency fruit by Vaclav Pech
Pick up the low-hanging concurrency fruitPick up the low-hanging concurrency fruit
Pick up the low-hanging concurrency fruit
Vaclav Pech870 views
Apache Flink & Graph Processing by Vasia Kalavri
Apache Flink & Graph ProcessingApache Flink & Graph Processing
Apache Flink & Graph Processing
Vasia Kalavri1.8K views
Things about Functional JavaScript by ChengHui Weng
Things about Functional JavaScriptThings about Functional JavaScript
Things about Functional JavaScript
ChengHui Weng324 views
Clojure: Practical functional approach on JVM by sunng87
Clojure: Practical functional approach on JVMClojure: Practical functional approach on JVM
Clojure: Practical functional approach on JVM
sunng871.7K views
Job Queue in Golang by Bo-Yi Wu
Job Queue in GolangJob Queue in Golang
Job Queue in Golang
Bo-Yi Wu22.3K views

More from Alexander Granin

Concurrent applications with free monads and stm by
Concurrent applications with free monads and stmConcurrent applications with free monads and stm
Concurrent applications with free monads and stmAlexander Granin
208 views55 slides
Hierarchical free monads and software design in fp by
Hierarchical free monads and software design in fpHierarchical free monads and software design in fp
Hierarchical free monads and software design in fpAlexander Granin
161 views59 slides
Monadic parsers in C++ by
Monadic parsers in C++Monadic parsers in C++
Monadic parsers in C++Alexander Granin
579 views58 slides
The present and the future of functional programming in c++ by
The present and the future of functional programming in c++The present and the future of functional programming in c++
The present and the future of functional programming in c++Alexander Granin
343 views125 slides
О разработке десктопных приложений / About desktop development by
О разработке десктопных приложений / About desktop developmentО разработке десктопных приложений / About desktop development
О разработке десктопных приложений / About desktop developmentAlexander Granin
437 views22 slides
Принципы и практики разработки ПО 2 / Principles and practices of software de... by
Принципы и практики разработки ПО 2 / Principles and practices of software de...Принципы и практики разработки ПО 2 / Principles and practices of software de...
Принципы и практики разработки ПО 2 / Principles and practices of software de...Alexander Granin
133 views23 slides

More from Alexander Granin(20)

Concurrent applications with free monads and stm by Alexander Granin
Concurrent applications with free monads and stmConcurrent applications with free monads and stm
Concurrent applications with free monads and stm
Alexander Granin208 views
Hierarchical free monads and software design in fp by Alexander Granin
Hierarchical free monads and software design in fpHierarchical free monads and software design in fp
Hierarchical free monads and software design in fp
Alexander Granin161 views
The present and the future of functional programming in c++ by Alexander Granin
The present and the future of functional programming in c++The present and the future of functional programming in c++
The present and the future of functional programming in c++
Alexander Granin343 views
О разработке десктопных приложений / About desktop development by Alexander Granin
О разработке десктопных приложений / About desktop developmentО разработке десктопных приложений / About desktop development
О разработке десктопных приложений / About desktop development
Alexander Granin437 views
Принципы и практики разработки ПО 2 / Principles and practices of software de... by Alexander Granin
Принципы и практики разработки ПО 2 / Principles and practices of software de...Принципы и практики разработки ПО 2 / Principles and practices of software de...
Принципы и практики разработки ПО 2 / Principles and practices of software de...
Alexander Granin133 views
Принципы и практики разработки ПО / Principles and practices of software deve... by Alexander Granin
Принципы и практики разработки ПО / Principles and practices of software deve...Принципы и практики разработки ПО / Principles and practices of software deve...
Принципы и практики разработки ПО / Principles and practices of software deve...
Alexander Granin140 views
Закон Деметры / Demetra's law by Alexander Granin
Закон Деметры / Demetra's lawЗакон Деметры / Demetra's law
Закон Деметры / Demetra's law
Alexander Granin149 views
GitHub - зеркало разработчика by Alexander Granin
GitHub - зеркало разработчикаGitHub - зеркало разработчика
GitHub - зеркало разработчика
Alexander Granin958 views
The Present and The Future of Functional Programming in C++ by Alexander Granin
The Present and The Future of Functional Programming in C++The Present and The Future of Functional Programming in C++
The Present and The Future of Functional Programming in C++
Alexander Granin86 views
Functional programming in C++ LambdaNsk by Alexander Granin
Functional programming in C++ LambdaNskFunctional programming in C++ LambdaNsk
Functional programming in C++ LambdaNsk
Alexander Granin464 views
Software transactional memory. pure functional approach by Alexander Granin
Software transactional memory. pure functional approachSoftware transactional memory. pure functional approach
Software transactional memory. pure functional approach
Alexander Granin968 views
Вы не понимаете ФП / You don't understand FP by Alexander Granin
Вы не понимаете ФП / You don't understand FPВы не понимаете ФП / You don't understand FP
Вы не понимаете ФП / You don't understand FP
Alexander Granin144 views
Functional "Life": parallel cellular automata and comonads by Alexander Granin
Functional "Life": parallel cellular automata and comonadsFunctional "Life": parallel cellular automata and comonads
Functional "Life": parallel cellular automata and comonads
Alexander Granin885 views
Functional microscope - Lenses in C++ by Alexander Granin
Functional microscope - Lenses in C++Functional microscope - Lenses in C++
Functional microscope - Lenses in C++
Alexander Granin1.7K views
Дизайн больших приложений в ФП by Alexander Granin
Дизайн больших приложений в ФПДизайн больших приложений в ФП
Дизайн больших приложений в ФП
Alexander Granin761 views
Линзы - комбинаторная манипуляция данными by Alexander Granin
Линзы - комбинаторная манипуляция даннымиЛинзы - комбинаторная манипуляция данными
Линзы - комбинаторная манипуляция данными
Alexander Granin389 views
Линзы - комбинаторная манипуляция данными (Dev2Dev) by Alexander Granin
Линзы - комбинаторная манипуляция данными (Dev2Dev)Линзы - комбинаторная манипуляция данными (Dev2Dev)
Линзы - комбинаторная манипуляция данными (Dev2Dev)
Alexander Granin483 views
Идиоматичный функциональный код by Alexander Granin
Идиоматичный функциональный кодИдиоматичный функциональный код
Идиоматичный функциональный код
Alexander Granin814 views

Recently uploaded

Micron CXL product and architecture update by
Micron CXL product and architecture updateMicron CXL product and architecture update
Micron CXL product and architecture updateCXL Forum
27 views7 slides
The Research Portal of Catalonia: Growing more (information) & more (services) by
The Research Portal of Catalonia: Growing more (information) & more (services)The Research Portal of Catalonia: Growing more (information) & more (services)
The Research Portal of Catalonia: Growing more (information) & more (services)CSUC - Consorci de Serveis Universitaris de Catalunya
66 views25 slides
"Ukrainian Mobile Banking Scaling in Practice. From 0 to 100 and beyond", Vad... by
"Ukrainian Mobile Banking Scaling in Practice. From 0 to 100 and beyond", Vad..."Ukrainian Mobile Banking Scaling in Practice. From 0 to 100 and beyond", Vad...
"Ukrainian Mobile Banking Scaling in Practice. From 0 to 100 and beyond", Vad...Fwdays
40 views30 slides
The Importance of Cybersecurity for Digital Transformation by
The Importance of Cybersecurity for Digital TransformationThe Importance of Cybersecurity for Digital Transformation
The Importance of Cybersecurity for Digital TransformationNUS-ISS
25 views26 slides
GigaIO: The March of Composability Onward to Memory with CXL by
GigaIO: The March of Composability Onward to Memory with CXLGigaIO: The March of Composability Onward to Memory with CXL
GigaIO: The March of Composability Onward to Memory with CXLCXL Forum
126 views12 slides
"Role of a CTO in software outsourcing company", Yuriy Nakonechnyy by
"Role of a CTO in software outsourcing company", Yuriy Nakonechnyy"Role of a CTO in software outsourcing company", Yuriy Nakonechnyy
"Role of a CTO in software outsourcing company", Yuriy NakonechnyyFwdays
40 views21 slides

Recently uploaded(20)

Micron CXL product and architecture update by CXL Forum
Micron CXL product and architecture updateMicron CXL product and architecture update
Micron CXL product and architecture update
CXL Forum27 views
"Ukrainian Mobile Banking Scaling in Practice. From 0 to 100 and beyond", Vad... by Fwdays
"Ukrainian Mobile Banking Scaling in Practice. From 0 to 100 and beyond", Vad..."Ukrainian Mobile Banking Scaling in Practice. From 0 to 100 and beyond", Vad...
"Ukrainian Mobile Banking Scaling in Practice. From 0 to 100 and beyond", Vad...
Fwdays40 views
The Importance of Cybersecurity for Digital Transformation by NUS-ISS
The Importance of Cybersecurity for Digital TransformationThe Importance of Cybersecurity for Digital Transformation
The Importance of Cybersecurity for Digital Transformation
NUS-ISS25 views
GigaIO: The March of Composability Onward to Memory with CXL by CXL Forum
GigaIO: The March of Composability Onward to Memory with CXLGigaIO: The March of Composability Onward to Memory with CXL
GigaIO: The March of Composability Onward to Memory with CXL
CXL Forum126 views
"Role of a CTO in software outsourcing company", Yuriy Nakonechnyy by Fwdays
"Role of a CTO in software outsourcing company", Yuriy Nakonechnyy"Role of a CTO in software outsourcing company", Yuriy Nakonechnyy
"Role of a CTO in software outsourcing company", Yuriy Nakonechnyy
Fwdays40 views
Webinar : Competing for tomorrow’s leaders – How MENA insurers can win the wa... by The Digital Insurer
Webinar : Competing for tomorrow’s leaders – How MENA insurers can win the wa...Webinar : Competing for tomorrow’s leaders – How MENA insurers can win the wa...
Webinar : Competing for tomorrow’s leaders – How MENA insurers can win the wa...
Liqid: Composable CXL Preview by CXL Forum
Liqid: Composable CXL PreviewLiqid: Composable CXL Preview
Liqid: Composable CXL Preview
CXL Forum121 views
Future of Learning - Yap Aye Wee.pdf by NUS-ISS
Future of Learning - Yap Aye Wee.pdfFuture of Learning - Yap Aye Wee.pdf
Future of Learning - Yap Aye Wee.pdf
NUS-ISS38 views
.conf Go 2023 - Data analysis as a routine by Splunk
.conf Go 2023 - Data analysis as a routine.conf Go 2023 - Data analysis as a routine
.conf Go 2023 - Data analysis as a routine
Splunk90 views
Architecting CX Measurement Frameworks and Ensuring CX Metrics are fit for Pu... by NUS-ISS
Architecting CX Measurement Frameworks and Ensuring CX Metrics are fit for Pu...Architecting CX Measurement Frameworks and Ensuring CX Metrics are fit for Pu...
Architecting CX Measurement Frameworks and Ensuring CX Metrics are fit for Pu...
NUS-ISS32 views
MemVerge: Gismo (Global IO-free Shared Memory Objects) by CXL Forum
MemVerge: Gismo (Global IO-free Shared Memory Objects)MemVerge: Gismo (Global IO-free Shared Memory Objects)
MemVerge: Gismo (Global IO-free Shared Memory Objects)
CXL Forum112 views
JCon Live 2023 - Lice coding some integration problems by Bernd Ruecker
JCon Live 2023 - Lice coding some integration problemsJCon Live 2023 - Lice coding some integration problems
JCon Live 2023 - Lice coding some integration problems
Bernd Ruecker67 views
Future of Learning - Khoong Chan Meng by NUS-ISS
Future of Learning - Khoong Chan MengFuture of Learning - Khoong Chan Meng
Future of Learning - Khoong Chan Meng
NUS-ISS31 views
How to reduce cold starts for Java Serverless applications in AWS at JCON Wor... by Vadym Kazulkin
How to reduce cold starts for Java Serverless applications in AWS at JCON Wor...How to reduce cold starts for Java Serverless applications in AWS at JCON Wor...
How to reduce cold starts for Java Serverless applications in AWS at JCON Wor...
Vadym Kazulkin70 views
MemVerge: Memory Viewer Software by CXL Forum
MemVerge: Memory Viewer SoftwareMemVerge: Memory Viewer Software
MemVerge: Memory Viewer Software
CXL Forum118 views
MemVerge: Past Present and Future of CXL by CXL Forum
MemVerge: Past Present and Future of CXLMemVerge: Past Present and Future of CXL
MemVerge: Past Present and Future of CXL
CXL Forum110 views
"AI Startup Growth from Idea to 1M ARR", Oleksandr Uspenskyi by Fwdays
"AI Startup Growth from Idea to 1M ARR", Oleksandr Uspenskyi"AI Startup Growth from Idea to 1M ARR", Oleksandr Uspenskyi
"AI Startup Growth from Idea to 1M ARR", Oleksandr Uspenskyi
Fwdays26 views

Transition graph using free monads and existentials

  • 1. Alexander Granin graninas@gmail.com eDSL for transition graph using Free monads and existential types
  • 3. Structure ● The problem ● Embedded DSLs design ● Transition Graph eDSL ● Sample application ● Implementation ● Why you shouldn’t write such code
  • 4. data FlowMethodF a s = RunUI (Interaction (UIResult s)) (UIResult s -> a) | ForkUI (Interaction (UIResult s)) a | CallAPI (Interaction (APIResult s)) (APIResult s -> a) | Get Store Key (Maybe String -> a) | Set Store Key String a | Fork (Flow s) (Control s -> a) | DoAff (forall eff. AppFlow eff s) (s -> a) | Await (Control s) (s -> a) | Delay Milliseconds a | OneOf (Array (Flow s)) (s -> a) | HandleError (Flow (ErrorHandler s)) (s -> a) | CheckPermissions (Array Permission) (PermissionStatus -> a) | TakePermissions (Array Permission) (Array PermissionResponse -> a) Presto Framework https://github.com/juspay/purescript-presto The problem
  • 5. Presto: flows billPayFlow :: MobileNumber -> ScreenFlow billPayFlow number = do amount <- UI.askAmount result <- Remote.payBill number amount billPayStatus number amount result billPayStatus :: MobileNumber -> Amount -> BillPayStatus -> ScreenFlow billPayStatus number amount status = do action <- runUI' (StatusScreen number amount status) case action of SuccessResult -> pure SuccessResult StatusScreenAbort -> billPayFlow number -- recursion
  • 6. BackT (MFlow) main = runBackT $ do lift $ log "Starting Run" a <- backPoint (randomInt 1 10) -- point to return lift $ log "A number" unless (a >= 9) $ BackT (pure GoBack) -- return from here b <- backPoint (randomInt 1 10) -- point to return lift $ log "Another number" unless (b >= 9) $ BackT (pure GoBack) -- return from here lift $ logShow (a + b) https://hackage.haskell.org/package/MFlow
  • 7. BackT + flows: how it could possibly look billPayFlow :: MobileNumber -> BackTScreenFlow billPayFlow number = do amount <- backPoint UI.askAmount -- point to return result <- lift $ Remote.payBill number amount billPayStatus number amount result billPayStatus :: MobileNumber -> Amount -> BillPayStatus -> BackTScreenFlow billPayStatus number amount status = do action <- lift $ runUI' (StatusScreen number amount status) case action of SuccessResult -> pure SuccessResult StatusScreenAbort -> BackT (pure GoBack) -- go back from here
  • 8. BackT: not a monad, actually -- https://gist.github.com/ninegua/97833cb4f82451f6c3db -- Unfortunately, BackT is not a monad. It violates the associative -- law, as the program shown below, test1 enters an infinite loop, -- and test2 exits after printing 3 lines. test1 = runBackT (a >> (b >> c)) test2 = runBackT ((a >> b) >> c) a = lift (print "step 1") >> breturn () b = lift (print "step 2") >> return () c = lift (print "step 3") >> fail ""
  • 10. 1. Make it look good 3 steps of eDSL design
  • 11. 1. Make it look good 2. Make it compile 3 steps of eDSL design
  • 12. 1. Make it look good 2. Make it compile 3. Make it work 3 steps of eDSL design
  • 13. detailsFlowTrans = trans detailsFlow </> [ onCalculate (trans calculateFlow) ] /> [ onClose (trans submitFlow ) ] detailsFlow :: Flow Int detailsFlow = pure 10 calculateFlow :: Int -> Flow Unit calculateFlow _ = pure unit submitFlow :: Int -> Flow Unit submitFlow _ = pure unit Inventing eDSL syntax, try #1
  • 14. homeFlowTrans = trans homeFlow <~> onClose (trans closeFlow) operationsFlowTrans = trans transactionFlow <~> onDetails (trans detailsFlow ) <~> onSettings (trans settingsFlow) ~> onHome homeFlowTrans Inventing eDSL syntax, try #2
  • 15. operationsFlowTrans = do t <- with transactionFlow backableTrans t onDetails (trans detailsFlow ) backableTrans t onSettings (trans settingsFlow) forwardOnlyTrans t onHome (trans homeFlow ) Maybe, monads?
  • 16. operationsFlowTrans = (forwardOnly (backable (backable (trans transactionFlow) (onDetails (trans detailsFlow)) ) (onSettings (trans settingsFlow)) ) (onHome (trans homeFlow)) ) Less is more. No syntax, please
  • 17. detailsFlowGraph :: Graph Unit Unit detailsFlowGraph = graph $ with detailsFlow <~> on "calculate" (leaf1 calculateFlow) ~> on "enter" (leaf1 submitFlow ) Final version of eDSL
  • 19. node1 :: Graph IO () () node1 = graph $ with (print "node1" >> getInput) <~> on "go 3" node3 ~> on "go 2" node2 /> node1 node2 :: Graph IO () () node2 = graph $ with (print "node2" >> nop) -/> node3 node3 :: Graph IO () () node3 = graph $ with (print "node3" >> getInput) </> node1 ~> on "exit" (leaf nop) getInput :: IO (Event, ()) getInput = do input <- getLine pure (input, ()) nop :: IO (Event, ()) nop = pure ("", ()) main = runGraph' id (== "back") node1 Sample: Graph + IO
  • 20. node1 :: Graph IO () Int node1 = graph $ with (pure ("", 100500)) -/> node2 node2 :: Graph IO Int () node2 = graph $ with1 (n -> print n >> getInput) <~> on "go 3" node3 /> node1 node3 :: Graph IO () () node3 = graph $ with (print "bye") -/> (leaf nop) getInput :: IO (Event, ()) getInput = do input <- getLine pure (input, ()) nop :: IO (Event, ()) nop = pure ("", ()) main = runGraph' id (== "back") node1 Typing
  • 21. (~>) By event, forward-only (<~>) By event, backable (uses a specified event to allow back transition) (>~<) By event, go forward and return unconditionally (/>) Default, forward-only (</>) Default, backable (-/>) Default, pass through node unconditionally (overrides other transitions) Transitions
  • 22. (~>) By event, forward-only (<~>) By event, backable (uses a specified event to allow back transition) (>~<) By event, go forward and return unconditionally (/>) Default, forward-only (</>) Default, backable (-/>) Default, pass through node unconditionally (overrides other transitions) Planned: (?/>) Default, with a given condition (!/>) Default, random with a given chance (!~>) By event, random with a given chance (?~>) By event, with a given condition (!?~>) By event, with a given condition, random with a given chance Transitions
  • 24. Game eDSL data AdventureLF next where GetUserInput :: (String -> next) -> AdventureLF next PrintMessage :: String -> next -> AdventureLF next GetObj :: FromJSON a => String -> (a -> next) -> AdventureLF next type AdventureL = Free AdventureLF
  • 25. Game eDSL data AdventureLF next where GetUserInput :: (String -> next) -> AdventureLF next PrintMessage :: String -> next -> AdventureLF next GetObj :: FromJSON a => String -> (a -> next) -> AdventureLF next type AdventureL = Free AdventureLF westOfHouse' :: (Bool, Bool) -> AdventureL () westOfHouse' (showDescr, showMailbox) = do mailbox :: Mailbox <- getObject "mailbox" printMessage "West of House" when showDescr $ printMessage "This is an open field west of a white house." when showMailbox $ printMessage $ describeObject mailbox
  • 26. type AGGraph a b = Graph AdventureL a b game :: AGGraph () () game = graph $ with (inputOnly (True, True)) -/> westOfHouse westOfHouse :: AGGraph (Bool, Bool) () westOfHouse = graph $ with1 (x -> westOfHouse' x >> getInput) ~> on "open mailbox" (openMailbox (False, False)) /> leaf nop openMailbox :: (Bool, Bool) -> AGGraph () () openMailbox houseView = graph $ with (evalAction MailboxType "open" "mailbox" >> inputOnly houseView) -/> westOfHouse Game transition graph
  • 27. Game output West of House This is an open field west of a white house, with a boarded front door. This is a small mailbox. A rubber mat saying 'Welcome to Zork!' lies by the door. > open mailbox Opening mailbox revealed leaflet > open mailbox Mailbox already opened.
  • 29. newtype Graph lang i o = Graph (Exists (GraphF lang i o)) data GraphF lang i o b = GraphF1 (i -> lang (Event, b)) (Transitions lang b o ()) data Exists f where Exists :: f a -> Exists f Graph: existential data type
  • 30. Graph lang i o Exists (GraphF lang i o)
  • 31. Graph lang i o Exists (GraphF lang i o) GraphF lang i o b
  • 32. Graph lang i o Exists (GraphF lang i o) GraphF lang i o b GraphF1 (i -> lang (Event, b)) (Transitions lang b o ())
  • 33. Graph lang i o Exists (GraphF lang i o) GraphF lang i o b GraphF1 (i -> lang (Event, b)) (Transitions lang b o ()) Transition (Graph lang b o) Exists (GraphF lang b o)
  • 34. Graph lang i o Exists (GraphF lang i o) GraphF lang i o b GraphF1 (i -> lang (Event, b)) (Transitions lang b o ()) Transition (Graph lang b o) Exists (GraphF lang b o) GraphF lang b o b2
  • 35. Graph lang i o Exists (GraphF lang i o) GraphF lang i o b GraphF1 (i -> lang (Event, b)) (Transitions lang b o ()) Transition (Graph lang b o) Exists (GraphF lang b o) GraphF lang b o b2 GraphF1 (b -> lang (Event, b2)) (Transitions lang b2 o ())
  • 36. module Data.Exists where import Unsafe.Coerce (unsafeCoerce) data Exists f where Exists :: f a -> Exists f mkExists :: forall f a. f a -> Exists f mkExists = unsafeCoerce runExists :: forall f r. (forall a. f a -> r) -> (Exists f -> r) runExists = unsafeCoerce Exists: hacky data type
  • 37. with1 :: (Monad lang) => (i -> lang (Event, b)) -> Transitions lang b o () -> Graph lang i o with1 langF1 table = Graph $ mkExists $ GraphF1 langF1 table case matchTransition event prevGraph of PassThrough (Graph graphEx) -> runExists (runTransition input) graphEx Construction and deconstruction of existential type
  • 38. with1 :: (Monad lang) => (i -> lang (Event, b)) -> Transitions lang b o () -> Graph lang i o node0 = graph $ with something <~> on "event 1" node1 ~> on "event 2" node2 >~< on "event 3" node3 </> node4 /> node5 Transitions data type
  • 39. type Transitions lang b o u = Free (TransitionF lang b o) u data TransitionF lang b o next = Transition Event (TransitionDef (Graph lang b o)) next | PassThroughTransition (Graph lang b o) next | PassDefaultForwardOnlyTransition (Graph lang b o) next | PassDefaultBackableTransition (Graph lang b o) next data TransitionDef graph = Backable graph | ForwardOnly graph | AutoBack graph | PassThrough graph | PassDefaultForwardOnly graph | PassDefaultBackable graph | NoTransition Transitions: Free monad data type
  • 40. interpret :: Event -> TransitionF lang b o u -> Interpreter (Graph lang b o) u interpret currentEvent (PassThroughTransition g next) = do transDef' <- get case transDef' of PassThrough _ -> pure next _ -> put (PassThrough g) >> pure next interpret currentEvent (PassDefaultBackableTransition g next) = do transDef' <- get case transDef' of NoTransition -> put (PassDefaultBackable g) >> pure next _ -> pure next Transitions interpreter (-/>) (</>)
  • 42. Running graph runTransition' :: (Monad m, Monad lang) => Runtime lang m -> ThisBackable -> AutoReturn -> i -> GraphF lang i o b -> m TransitionResult runTransition' runtime backable autoReturn i3 g3 = do let f3 = getLang i3 g3 transitionResult <- runTransition runtime autoReturn f3 g3 case transitionResult of Done -> pure Done AutoFallbackRerun -> pure FallbackRerun FallbackRerun -> runTransition' runtime backable thisNotAutoReturn i3 g3 Fallback -> if isBackable backable then pure FallbackRerun else pure Done -- throw "No fallback" GoForward e2 i3 -> case matchTransition e2 g2 of NoTransition -> pure Done PassThrough g3@(Graph g3Ex) -> runExists (runTransition' runtime thisNotBackable thisNotAutoReturn i3) g3Ex PassDefaultForwardOnly g3@(Graph g3Ex) -> runExists (runTransition' runtime thisNotBackable thisNotAutoReturn i3) g3Ex PassDefaultBackable g3@(Graph g3Ex) -> runExists (runTransition' runtime thisBackable thisNotAutoReturn i3) g3Ex Backable g3@(Graph g3Ex) -> runExists (runTransition' runtime thisBackable thisNotAutoReturn i3) ForwardOnly g3@(Graph g3Ex) -> runExists (runTransition' runtime thisNotBacka AutoBack g3@(Graph g3Ex) -> runExists (runTransit runLang :: (Monad m, Monad lang) => Runtime lang m -> lang (LangOutput a) -> m (LangResult Event a) runLang (Runtime runLang isBackEvent) lang = do(e, i) <- runLang lang if isBackEvent e then pure GoBackward else pure $ GoForward e i data Runtime lang m = Runtime { runLang_ :: Runner lang m , isBackEvent_ :: Event -> Bool } data LangResult a b = GoForward a b | GoBackward data TransitionResult = Fallback | AutoFallbackRerun | FallbackRerun | Done
  • 43. Why you shouldn’t write such code ● Exists is hack Use GADTs
  • 44. Why you shouldn’t write such code ● Exists is hack Use GADTs ● Overengineering Kmettism is out there
  • 45. Why you shouldn’t write such code ● Exists is hack Use GADTs ● Overengineering Kmettism is out there ● Overengineering - 2 Free monad can be replaced by Map or list
  • 46. Why you shouldn’t write such code ● Exists is hack Use GADTs ● Overengineering Kmettism is out there ● Overengineering - 2 Free monad can be replaced by Map ● Don't reinvent the wheel Use generic libraries for graphs
  • 47. Why you shouldn’t write such code ● Exists is hack Use GADTs ● Overengineering Kmettism is out there ● Overengineering - 2 Free monad can be replaced by Map ● Don't reinvent the wheel Use generic libraries for graphs ● Don't reinvent the wheel - 2 You probably need FRP
  • 48. Why you shouldn’t write such code ● Exists is hack Use GADTs ● Overengineering Kmettism is out there ● Overengineering - 2 Free monad can be replaced by Map ● Don't reinvent the wheel Use generic libraries for graphs ● Don't reinvent the wheel - 2 You probably need FRP ● Don't reinvent the wheel - 3 Is Graph In Out type just the Arrow In Out type?
  • 49. Why you shouldn’t write such code ● Exists is hack Use GADTs ● Overengineering Kmettism is out there ● Overengineering - 2 Free monad can be replaced by Map ● Don't reinvent the wheel Use generic libraries for graphs ● Don't reinvent the wheel - 2 You probably need FRP ● Don't reinvent the wheel - 3 Is Graph In Out type just the Arrow In Out type? ● Don’t reinvent the wheel - 4 It’s just a State Machine, isn’t it?
  • 50. Everyone knows that debugging is twice as hard as writing a program in the first place. So if you're as clever as you can be when you write it, how will you ever debug it? Brian Kernighan