packages feed

fractal-layer-0.1.0.0: README.md

# 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