Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

affineStore function #130

Open
kim366 opened this issue Apr 15, 2021 · 1 comment
Open

affineStore function #130

kim366 opened this issue Apr 15, 2021 · 1 comment

Comments

@kim366
Copy link

kim366 commented Apr 15, 2021

I was looking for a function similar to lensStore but where some constructors of the ADT did not contain the inner value. After a day of learning lenses I came up with the following:

affineStore
  :: forall s t t' a b
   . (t' -> t)
  -> ALens s t' a b
  -> s
  -> Tuple (b -> t) (Either t a)
affineStore f l = withLens l go
  where
  go get set value =
    Tuple
      (f <<< set value)
      (Right $ get value)

ignoredAffineStore :: forall t a b. t -> Tuple (b -> t) (Either t a)
ignoredAffineStore wrapper = Tuple (const wrapper) (Left wrapper)

data Adt
  = X { x :: Int, y :: String }
  | Y { a :: Int, b :: Number }
  | Z { e :: Char }

_x :: forall s r. Lens' { x :: s | r } s
_x = prop (Proxy :: _ "x")

_a :: forall s r. Lens' { a :: s | r } s
_a = prop (Proxy :: _ "a")

_valueInAdt :: AffineTraversal' Adt Int
_valueInAdt = affineTraversal' case _ of
    X value   -> affineStore X _x value
    Y value   -> affineStore Y _a value
    adt@(Z _) -> ignoredAffineStore adt

Here the functions affineStore and ignoredAffineStore can be used in a similar way to lensStore. I have checked that it all follows affine traversal laws, I can send over the tests.

My question is whether these are useful functions to have in the lenses package. It is very useful for what I'm building and it seems there is no other way of doing it this comfortably.

@kim366
Copy link
Author

kim366 commented Apr 16, 2021

After developing a affineStore' function accepting prisms/affine traversals, I found out that an affine traversal is a superset of a lens. So here is the more general version:

affineStore
  :: forall s t a b
   . (s -> t)
  -> (AnAffineTraversal s s a b)
  -> s
  -> Tuple (b -> t) (Either t a)
affineStore f l = withAffineTraversal l go
  where
  go setl previewl value =
    Tuple
      (f <<< setl value)
      (lmap f $ previewl value)

data Adt
  = X { x :: Int, y :: String }
  | Y { a :: Maybe Int, b :: Number }
  | Z { e :: Char }
  | W (Maybe Int)

derive instance genericAdt :: Generic Adt _
derive instance eqAdt :: Eq Adt
instance showAdt :: Show Adt where show = genericShow

_x :: forall s r. Lens' { x :: s | r } s
_x = prop (Proxy :: _ "x")

_a :: forall s r. AffineTraversal' { a :: Maybe s | r } s
_a = prop (Proxy :: _ "a") <<< _Just

_valueInAdt :: AffineTraversal' Adt Int
_valueInAdt = affineTraversal' case _ of
    X value   -> affineStore X _x value
    Y value   -> affineStore Y _a value
    W value   -> affineStore W _Just value
    adt@(Z _) -> ignoredAffineStore adt

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

1 participant