# fractal-layer
Composable, type-safe resource management and dependency injection for
Haskell, inspired by [ZIO's ZLayer](https://zio.dev/reference/contextual/zlayer).
## The idea
A `Layer m deps env` is a recipe for building a value of type `env` from
dependencies `deps`, with automatic resource cleanup. Think of it as
`deps -> m env` plus a finaliser that runs when the scope ends.
```haskell
configLayer :: Layer IO () Config
dbLayer :: Layer IO Config Database
cacheLayer :: Layer IO Config Cache
```
Each layer declares exactly what it needs and what it produces. The
compiler enforces correct wiring at every composition site.
## Composition
Layers compose via standard Haskell typeclasses:
```haskell
-- sequential: config feeds into db and web
appLayer :: Layer IO () (Config, (Database, WebServer))
appLayer = configLayer >>> (dbLayer &&& webLayer)
-- fallback: try remote, fall back to local
dbLayer :: Layer IO Config Database
dbLayer = remotePostgres <|> localSQLite
```
`(&&&)` runs both sides concurrently. `(<|>)` cleans up the failed
branch before trying the fallback.
## Services (shared singletons)
When two layers need the same expensive resource, `Service` gives you
at-most-once initialisation with automatic sharing:
```haskell
poolService :: Service IO Config ConnectionPool
poolService = mkService $ do
cfg <- ask
resource (createPool cfg) drainPool
webLayer :: Layer IO Config WebServer
webLayer = do
pool <- service poolService -- creates the pool
resource (startWeb pool) stopWeb
apiLayer :: Layer IO Config ApiServer
apiLayer = do
pool <- service poolService -- reuses the same pool
resource (startApi pool) stopApi
```
## Running
```haskell
main :: IO ()
main = withLayer () appLayer $ \(cfg, (db, ws)) ->
serveRequests ws
-- all resources released here, in reverse acquisition order
```
## Documentation
See the Haddock docs on `Fractal.Layer` for a full walkthrough with
examples.
## License
BSD-3-Clause