polytropos-reader-soup: Composable multi-context Reader monad with zero-overhead row polymorphism

[ control, library, monads, records ] [ Propose Tags ] [ Report a vulnerability ]

A composable, extensible multi-context Reader environment for polytropos. Instead of defining exponentially growing MonadFoo / MonadBar type class stacks or deeply nested ReaderT hierarchies, Polytropos.ReaderSoup.ReaderSoup collects all application contexts in a single flat contiguous row (Polytropos.Record). . Inspired by and acknowledging Yves Parès's pioneering reader-soup package from the porcupine ecosystem, re-architected from scratch on top of Polytropos's high-performance flat array representation (Polytropos.Core.Rep) and compile-time dictionary synthesis (Polytropos.Plugin). . Key Features: . * Flat multi-context environment (Polytropos.ReaderSoup.ReaderSoup) backed by Polytropos's $O(1)$ flat array representation. * Direct context access (Polytropos.ReaderSoup.askSoup) via type-level labels or OverloadedRecordDot. * Structural sub-soup slicing (Polytropos.ReaderSoup.filtering) via compile-time Polytropos.SubRow projection. * Single-context projection (Polytropos.ReaderSoup.Spoon) giving standard MonadReader instances for isolated subsystems. * Context bridging (Polytropos.ReaderSoup.SoupContext) with Polytropos.ReaderSoup.picking, Polytropos.ReaderSoup.scooping, and Polytropos.ReaderSoup.pouring. * Modular runner composition (Polytropos.ReaderSoup.ContextRunner, Polytropos.ReaderSoup.consumeSoup). * Resource management integration (Polytropos.ReaderSoup.Resource) supporting resourcet's Control.Monad.Trans.Resource.ResourceT. . Start at the front door module Polytropos.ReaderSoup for comprehensive documentation and worked examples.


[Skip to Readme]

Downloads

Maintainer's Corner

Package maintainers

For package maintainers and hackage trustees

Candidates

  • No Candidates
Versions [RSS] 0.1.0.2
Change log CHANGELOG.md
Dependencies base (>=4.14 && <5), exceptions (>=0.10 && <0.11), monad-control (>=1.0 && <1.1), mtl (>=2.2 && <2.4), polytropos-core (>=0.1 && <0.2), polytropos-plugin (>=0.1 && <0.2), primitive (>=0.8 && <1.0), resourcet (>=1.2 && <1.4), safe-exceptions (>=0.1 && <0.2), transformers (>=0.5 && <0.7), transformers-base (>=0.4 && <0.5), unliftio (>=0.2 && <0.3), unliftio-core (>=0.2 && <0.3) [details]
License (EUPL-1.2 OR Apache-2.0)
Author Nadia Yvette Chambers
Maintainer nadia.yvette.chambers@ik.me
Uploaded by nyc at 2026-10-21T21:34:39Z
Category Control, Monads, Records
Home page https://github.com/NadiaYvette/polytropos
Bug tracker https://github.com/NadiaYvette/polytropos/issues
Source repo head: git clone https://github.com/NadiaYvette/polytropos(packages/polytropos-reader-soup)
Distributions
Downloads 3 total (3 in the last 30 days)
Rating (no votes yet) [estimated by Bayesian average]
Your Rating
  • λ
  • λ
  • λ
Status Docs available [build log]
Last success reported on 2026-10-21 [all 1 reports]

Readme for polytropos-reader-soup-0.1.0.2

[back to package description]

polytropos-reader-soup

Composable multi-context Reader monad with zero-overhead row polymorphism for polytropos.

Overview

In traditional Haskell application design, managing multiple configuration environments, connection pools, and runtime capabilities typically forces one of two unsatisfactory choices:

  1. MTL Class Proliferation: Defining distinct MonadDatabase, MonadConfig, MonadLogger, MonadMetrics classes with \(O(N^2)\) quadratic boilerplate instances across every layer of the transformer stack.
  2. Monolithic AppEnv: Bundling everything into a single nominal AppEnv record, coupling small, self-contained sub-routines to the entire global environment and hindering modularity.

polytropos-reader-soup solves this dilemma by re-architecting Yves Parès's reader-soup on top of Polytropos's high-performance flat contiguous array representation (Polytropos.Core.Rep). A ReaderSoup hosts an arbitrary open row of labeled contexts in a single ReaderT (Record ctxs) IO layer. Subsystems declare exactly the slice of contexts they require, accessing them in \(O(1)\) time via compile-time synthesized dictionary offsets, with structural narrowing via filtering taking \(O(K)\) flat array copy time.

Features

  • ReaderSoup: Single-layer multi-context Reader environment (ReaderT (Record ctxs) IO a).
  • askSoup: \(O(1)\) context retrieval using type-level label symbols or OverloadedRecordDot.
  • filtering: Zero-boilerplate structural subtyping via SubRow, allowing sub-actions to run seamlessly inside larger environments.
  • Spoon: Isolates a single labeled context from the broth and equips it with a standard MonadReader instance supporting ask and local.
  • SoupContext: Bridges existing third-party ReaderT-like monads (e.g. ResourceT, KatipContextT) via picking, scooping, and pouring.
  • consumeSoup: Composes modular ContextRunner handlers to peel and execute contexts sequentially until the base broth is reached.
  • Polytropos.ReaderSoup.Resource: Turnkey resourcet integration with SoupContext InternalState ResourceT and MonadResource instances.

Quick Example

{-# LANGUAGE DataKinds #-}
{-# LANGUAGE OverloadedRecordDot #-}
{-# LANGUAGE OverloadedStrings #-}
{-# OPTIONS_GHC -fplugin=Polytropos.Plugin #-}

module Main where

import Control.Monad.IO.Class (liftIO)
import Polytropos
import Polytropos.ReaderSoup

data DBConn = DBConn String
data Logger = Logger (String -> IO ())

type AppCtx =
  '[ "db"     := DBConn
   , "logger" := Logger
   , "port"   := Int
   ]

-- | A database worker only requires the DBConn context:
runQuery :: ReaderSoup '[ "db" := DBConn ] String
runQuery = do
  DBConn connStr <- askSoup (Field @"db")
  pure ("Executed on " ++ connStr)

-- | Main application running with the full AppCtx:
app :: ReaderSoup AppCtx ()
app = do
  Logger logFn <- askSoup (Field @"logger")
  liftIO (logFn "Application starting...")

  -- Narrow the environment from AppCtx down to '[ "db" := DBConn ]:
  res <- filtering runQuery
  liftIO (logFn ("Query result: " ++ res))

main :: IO ()
main = do
  let env = insertField (Field @"db") (DBConn "postgres://localhost:5432/prod")
          $ insertField (Field @"logger") (Logger putStrLn)
          $ insertField (Field @"port") (8080 :: Int)
          $ emptyRecord

  runReaderSoup app env

Attribution & Precedents

This package is inspired by and directly acknowledges Yves Parès's work on reader-soup within the Porcupine pipeline framework. The original package pioneered the concept of representing open collections of Reader-like monads via Vinyl extensible records. polytropos-reader-soup preserves those ergonomic and architectural insights while re-grounding them entirely on Polytropos's native flat array physics, compile-time literal index resolution, and structural SubRow evidence synthesis.

License

Dual-licensed under EUPL-1.2 OR Apache-2.0.