| Copyright | (c) 2026 The Polytropos Authors |
|---|---|
| License | EUPL-1.2 OR Apache-2.0 |
| Maintainer | nadia.yvette.chambers@ik.me |
| Stability | experimental |
| Portability | non-portable (GHC extensions) |
| Safe Haskell | None |
| Language | GHC2021 |
Polytropos.Optics
Description
Integration between polytropos and the optics / optics-core ecosystem.
This module provides first-class optics for open records and variants:
* Van Laarhoven lenses for record fields via fieldLens.
* First-class prisms for variant constructors via ctorOptic.
* Overloaded labels (LabelOptic) allowing #fieldname lens syntax with OverloadedLabels.
Architectural Overview & Rationale
Rather than treating record fields as string lookups in runtime maps, polytropos-optics
relies on the literal zero-based slot indices synthesized by polytropos-plugin.
Each lens focuses directly on an array slot in the underlying contiguous SmallArray.
Prisms inspect the unboxed constructor tag in \(O(1)\) and extract the constructor's payload.
When to Use This Module
- When your application uses the
opticslibrary and you want idiomatic lens and prism operations overpolytroposrecords and variants. - When you want
#fieldNamesyntax for record field access and update.
When Not to Use This Module
- If your project is built around Edward Kmett's
lenslibrary, use Polytropos.Lens instead. - If your project aims for minimal dependencies and uses
microlens, use Polytropos.Microlens instead.
Worked Example
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE OverloadedLabels #-}
{-# LANGUAGE TypeApplications #-}
{-# OPTIONS_GHC -fplugin=Polytropos.Plugin #-}
import Optics.Core
import Polytropos
import Polytropos.Optics
type Person = Record '["name" ':= String, "age" ':= Int]
alice :: Person
alice = REC { name = "Alice", age = 30 }
-- Reading via overloaded label:
aliceAge :: Int
aliceAge = alice ^. #age -- 30
-- Updating via overloaded label:
olderAlice :: Person
olderAlice = alice & #age %~ (+ 1) -- age = 31
-- Working with variant prisms:
type Shape = Variant '["Circle" ':= '["radius" ':= Double]]
myCircle :: Shape
myCircle = VAR { Circle = REC { radius = 5.0 } }
circleRadius :: Maybe Double
circleRadius = preview (ctorOptic (Field @"Circle") % #radius) myCircle -- Just 5.0Record Field Lenses
fieldLens :: forall (n :: Symbol) (r :: Row) a. FieldIndex n r a => Field n -> LensVL (Record r) (Record r) a a Source #
Van Laarhoven lens for a record field specified by label.
Variant Constructor Prisms
ctorOptic :: forall (c :: Symbol) (s :: SumRow) (fs :: Row). ConstructorIndex c s => Field c -> Optic A_Prism NoIx (Variant s) (Variant s) (Record fs) (Record fs) Source #
Prism optic for a variant constructor specified by label.