polytropos-optics
Copyright(c) 2026 The Polytropos Authors
LicenseEUPL-1.2 OR Apache-2.0
Maintainernadia.yvette.chambers@ik.me
Stabilityexperimental
Portabilitynon-portable (GHC extensions)
Safe HaskellNone
LanguageGHC2021

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 optics library and you want idiomatic lens and prism operations over polytropos records and variants.
  • When you want #fieldName syntax for record field access and update.

When Not to Use This Module

  • If your project is built around Edward Kmett's lens library, 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.0
Synopsis

Record 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.

Orphan instances

(KnownSymbol n, HasField n (Record r) field, FieldIndex n r field, a ~ field, b ~ field) => LabelOptic n A_Lens (Record r) (Record r) a b Source # 
Instance details

Methods

labelOptic :: Optic A_Lens NoIx (Record r) (Record r) a b #