Skip to content

Lens won't work as expected due to the missing Functor (FUN 'One a) instance (both Data and Control) #459

@konn

Description

@konn

Describe the bug

In my code, I have implemented the following utility which looks similar those of lens:

import Control.Functor.Linear

zoom ::
  (Functor m) =>
  Optics.Optic_ (Kleisli (Compose ((,) t) (FUN 'One t))) s s t t ->
  StateT t m a %1 ->
  StateT s m a
{-# INLINE zoom #-}
zoom l (StateT f) = StateT \ !s0 ->
  Optic.reifyLens l s0 & \(!t, !back) ->
    fmap back <$> f t

infix 4 %=

(%=) ::
  (Applicative m) =>
  Optics.Optic_ (Kleisli (Compose ((,) t) (FUN 'One t'))) s s t t' ->
  (t %1 -> t') %1 ->
  StateT s m ()
{-# INLINE (%=) #-}
l %= f = StateT \s0 ->
  Optic.reifyLens l s0 & \(!t, !back) ->
    pure ((), back $! f t)

That is, zoom zoomes internal state with linear lens, and (%=) linearly modifies internal state by lens.

Those combinators should work with Lenses made with Control.Optics.Linear.Lens.lens, but they don't due to the lack of Functor (FUN 'One) instances (both for Data.Functor.Linear and Control.Functor.Linear).

To Reproduce

Suppose we have following:

data Foo where Foo :: Int %1 -> Foo

fooIntL :: Opt.Lens' Foo Int
fooIntL = lens \(Foo i) -> (i, Foo)

stepBy :: Int -> State Foo ()
stepBy i = fooIntL %= (+ i)

This throws a type error:

 No instance for (Control.Functor.Linear.Internal.Class.Functor
                     (FUN 'One Int))
    arising from a use of fooIntL

Expected behavior

This must not throw a type error.
Indeed, the error disappears once we have added the following:

instance D.Functor (FUN 'One t) where
  fmap = (.)

instance Functor (FUN 'One t) where
  fmap = (.)

Environment

  • OS name + version: macOS Ventura 13.4.1
  • Version of the code: linear-base 0.3.1 (+ GHC 9.4)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions