Shoehorning dependency injection
into a FP language, what does it take?
Eric Torreborre
Dependency injection and FP?
DON’T COME NEAR MY FUNCTIONS, YOU PUNK!
Dependency injection and FP
What have we done here?
Interface
Implementation
implements
Dependency
depends on
Component Based Development
One function alone does not
always make sense by itself!
Interface
Composition FTW
Decomposition?
Configuration detail?
Different filtering logic?
Debug summary?
Simplified discount rules?
Large applications
A transaction engine
Large applications
A transaction engine
The logger is here!
Large data models
Data generators? Encoders/decoders?
Large data models
How about generating
data for users in a given city
with a specific price?
What did we try?
Service locator
Annotations +
reflection
What did we try?
Typeclasses /
implicits
Effect
libraries
What did we try?
Declare
dependencies
Wire
dependencies
What makes DI “good”?
Locality Typechecking
Incrementality Effects
Targeted
overrides
Locality
Adding a dependency is immediate
And limited to the strict necessary!
Incrementality
Modifying the wiring must be possible without touching it
Can I define a “dev” profile
reusing that code as-is?
Typechecking
The compiler must tell us if a dependency is missing
Not this!
Targeted overrides
Any part of the graph can be overridden
The same component type can have different implementations
Or all of this
Just this
Targeted overrides
Any part of the graph can be overridden
The same component type can have different implementations
Should this concrete
implementation be specified here?
Effects
Instantiation can be effectful
Instances can be singletons or not
Singleton is the default
Java = unrestricted effects 🤪
Code at our fingertips!
Expressivity
Conciseness
Fast, accurate
feedback
DI in Unison
What is Unison?
Strongly, statically typed
Haskell-like but
- Strict evaluation
- No type-classes
- No macros
Functional programming language
Immutable code
- Content-hashed
- Stored in a database With an effect system!
Unison Cloud
No ORM for persistence
Deploy services with code!
- Abstract notion of Location
- Run locally for testing
- Easy rollback / versioning
Services communicating with no JSON
Distributed code
- Services / daemons
- Pipelines, KLogs (distributed streaming)
Unison syntax primer
Unison abilities
continuation
Having an effect
https://okmij.org/ftp/Computation/having-effect.html
Unison abilities
IO
Abort, Exception, Throw
Store
Remote
Stream
Random Each
A client application
Http
Logger
Configuration
Authenticator
Level
Application
Accounts
Top-level logic
Accounts API
Auth. logic
Keys
GET, POST
info, debug, error,…
A component interface
Runtime effects (abstract)
Concrete effect
An implementation
implementation-specific
effect
dependencies
Abstracting over dependencies
dependencies as
effects
Wiring dependencies
constructor expression
initial configuration
make the top-level application!
result
Default wiring
Wiring dependencies
build or retrieve from the store
Stateful creation of components
Constructors
Build effect
Built component
For which
type/build effect?
How to build
a value?
What’s provided? What the
“common stack”?
Untyped internals
provided components
phantom type for a list of abilities
build a
value
store the built value
runtime effects
untyped
values
User-side vs library-side
4 declarations per
component
1 line per
component
Profit?
Locality?
Yes, But
No simple call anymore
Incremental?
Yes
just add a new
value/constructor
Typechecked?
Yes,
all components and
effects are listed
And
only typechecks if the
component is available!
Effectful creation?
additional effects
are returned
Yes, But
Cycles are not
statically typechecked!
Targeted overrides?
setValueAt,
setConstructorAt
p
a
t
h
=
[
A
p
p
l
i
c
a
t
i
o
n
,
A
c
c
o
u
n
t
s
,
A
u
t
h
e
n
t
i
c
a
t
o
r
]
Can we do better?
Why does this work?
Abilities / expression language
Dynamic types
Phantom types
Why does this work?
Type-level sets of types / effects
Abstract list of effects
Inferred list
of effects
Do better in Unison?
Type aliases
Do better in Unison?
Override component effects
➕
=
Collect function types: parameters + effects
Do better in Unison?
Full dynamic types
It’s functions all the way down
Do better ideally
Meta-programming Decompose / apply functions
Custom compiler errors Stack can become large
(Efficient) type-level sets https://xkcd.com/303
Good inference options =
if prod then … else …
Please PL designers,
give us just enough
meta-programming!
Thanks!

Shoehorning dependency injection into a FP language, what does it take?