tower-hs 0.3.0.0 → 0.3.0.1
raw patch · 3 files changed
+26/−41 lines, 3 filesdep +transformers
Dependencies added: transformers
Files
- CHANGELOG.md +5/−0
- src/Tower/Service.hs +19/−40
- tower-hs.cabal +2/−1
CHANGELOG.md view
@@ -1,5 +1,10 @@ # Changelog +## 0.3.0.1 — 2026-04-08++- Refactor: derive `Functor`, `Profunctor`, `Category`, `Arrow`, and `ArrowChoice` for `Service` via `Kleisli (ExceptT ServiceError IO)`, to which `Service` is isomorphic. No behavioral or API changes — all instances match the prior hand-written semantics exactly (including `Left` short-circuit on `>>>`, `first`, and `left`).+- New transitive dependency: `transformers` (GHC boot library).+ ## 0.3.0.0 — 2026-04-07 - Add `Category` instance for `Service` — compose services sequentially with `>>>`, errors short-circuit automatically
src/Tower/Service.hs view
@@ -1,3 +1,5 @@+{-# LANGUAGE DerivingVia #-}+ -- | -- Module : Tower.Service -- Description : Core Service and Middleware abstractions@@ -9,7 +11,8 @@ -- -- 'Service' forms a 'Category' (sequential composition via '>>>') and an -- 'Arrow', so you can use arrow combinators and proc-notation to wire--- services together.+-- services together. All instances are derived via+-- @'Kleisli' ('ExceptT' 'ServiceError' 'IO')@, which 'Service' is isomorphic to. module Tower.Service ( Service(..) , Middleware@@ -19,19 +22,25 @@ , composeMiddleware ) where -import Control.Arrow (Arrow(..), ArrowChoice(..))-import Control.Category (Category(..))+import Control.Arrow (Arrow, ArrowChoice, Kleisli(..))+import Control.Category (Category, (.))+import Control.Monad.Trans.Except (ExceptT(..)) import Data.Profunctor (Profunctor(..))+import GHC.IO (IO(..)) -- bring IO's newtype constructor into scope so DerivingVia can coerce through it import Prelude hiding (id, (.)) import Tower.Error (ServiceError) -- | A service transforms a request into an effectful response. -- This is the fundamental building block — middleware wraps services. ----- 'Service' is a 'Functor' in its response type and a 'Profunctor' over--- both request and response types. Use 'fmap' to transform responses,--- 'lmap' to transform requests, or 'dimap' to transform both — useful for--- lifting a @Service Http.Request Http.Response@ into a+-- 'Service' is isomorphic to @'Kleisli' ('ExceptT' 'ServiceError' 'IO')@,+-- and all of its instances ('Functor', 'Profunctor', 'Category', 'Arrow',+-- 'ArrowChoice') are derived from that representation. Composition via+-- '>>>' short-circuits on the first 'Left'.+--+-- Use 'fmap' to transform responses, 'lmap' to transform requests, or+-- 'dimap' to transform both — useful for lifting a+-- @Service Http.Request Http.Response@ into a -- @Service MyBinding.SomeRequest MyBinding.SomeResponse@. -- -- @@@ -43,39 +52,9 @@ { runService :: req -> IO (Either ServiceError res) -- ^ Execute the service with a request, returning either an error or a response. }--instance Functor (Service req) where- fmap f (Service run) = Service $ \req -> fmap (fmap f) (run req)--instance Profunctor Service where- dimap f g (Service run) = Service $ \req -> fmap (fmap g) (run (f req))- lmap f (Service run) = Service (run . f)- rmap = fmap--instance Category Service where- id = Service (pure . Right)- (Service g) . (Service f) = Service $ \req -> do- result <- f req- case result of- Left err -> pure (Left err)- Right mid -> g mid--instance Arrow Service where- arr f = Service (pure . Right . f)- first (Service f) = Service $ \(a, c) -> do- result <- f a- case result of- Left err -> pure (Left err)- Right b -> pure (Right (b, c))--instance ArrowChoice Service where- left (Service f) = Service $ \eac -> case eac of- Left a -> do- result <- f a- case result of- Left err -> pure (Left err)- Right b -> pure (Right (Left b))- Right c -> pure (Right (Right c))+ deriving (Functor) via (Kleisli (ExceptT ServiceError IO) req)+ deriving (Profunctor, Category, Arrow, ArrowChoice)+ via (Kleisli (ExceptT ServiceError IO)) -- | Middleware wraps a service to add behavior (retry, timeout, logging, etc.) --
tower-hs.cabal view
@@ -5,7 +5,7 @@ -- see: https://github.com/sol/hpack name: tower-hs-version: 0.3.0.0+version: 0.3.0.1 synopsis: Composable service middleware for Haskell, inspired by Rust's Tower description: tower-hs provides a composable middleware abstraction for any service type. Build middleware stacks with retry, timeout, circuit breaker, and more — all with@@ -57,6 +57,7 @@ , stm ==2.5.* , text >=2.0 && <2.2 , time >=1.11 && <1.15+ , transformers >=0.5 && <0.7 default-language: Haskell2010 test-suite tower-hs-test