-
Notifications
You must be signed in to change notification settings - Fork 24
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
Restrict over', iover', and set' to traversals #475
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -63,10 +63,10 @@ module Optics.Setter | |
) where | ||
|
||
import Data.Profunctor.Indexed | ||
import Data.Tuple.Solo (Solo (..), getSolo) | ||
|
||
import Optics.Internal.Optic | ||
import Optics.Internal.Setter | ||
import Optics.Internal.Utils | ||
|
||
-- | Type synonym for a type-modifying setter. | ||
type Setter s t a b = Optic A_Setter NoIx s t a b | ||
|
@@ -102,14 +102,28 @@ over o = \f -> runFunArrow $ getOptic (castOptic @A_Setter o) (FunArrow f) | |
-- 'over' is used, because the first coordinate of a pair is never forced. | ||
-- | ||
over' | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The haddocks above here have another "TODO DOC" it would be great to nail along with this. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The intuition is that each target result is forced before producing the full result. More precisely, I believe over' p f xs = forceElements res `seq` res
where
forceElements = foldrOf p seq ()
res = over p f xs There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That "law" only works with a non-type-changing traversal, but I think it's a good way to express the concept. |
||
:: Is k A_Setter | ||
:: Is k A_Traversal | ||
=> Optic k is s t a b | ||
-> (a -> b) -> s -> t | ||
-- See [Note: Solo wrapping] | ||
over' o = \f -> | ||
let star = getOptic (castOptic @A_Setter o) $ Star (wrapIdentity' . f) | ||
in unwrapIdentity' . runStar star | ||
let star = getOptic (castOptic @A_Traversal o) $ Star ((Solo $!) . f) | ||
in getSolo . runStar star | ||
Comment on lines
104
to
+111
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we move There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. They would be a better fit, probably; I was just trying to avoid breaking things unnecessarily. |
||
{-# INLINE over' #-} | ||
|
||
-- Note: Solo wrapping | ||
-- | ||
-- We use Solo for strict application of (indexed) setters. | ||
-- | ||
-- Credit for this idea goes to Eric Mertens; see | ||
-- <https://github.com/glguy/irc-core/commit/2d5fc45b05f1>. | ||
-- | ||
-- Using Solo rather than Identity allows us, when applying a traversal to a | ||
-- structure, to evaluate only the parts that we modify. If an optic focuses on | ||
-- multiple targets, the Applicative instance of Solo (combined with applying | ||
-- the Solo data constructor strictly) makes sure that we force evaluation of | ||
-- all of them, but we leave anything else alone. | ||
|
||
-- | Apply a setter. | ||
-- | ||
-- @ | ||
|
@@ -128,10 +142,11 @@ set o = over o . const | |
|
||
-- | Apply a setter, strictly. | ||
-- | ||
-- TODO DOC: what exactly is the strictness property? | ||
-- | ||
-- The new value will be forced if and only if the optic traverses at | ||
-- least one target. If forcing the new value is inexpensive, then it | ||
-- is cheaper to do so manually and use 'set'. | ||
Comment on lines
+145
to
+147
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I wonder if we could easily test this, since we didn't before and apparently didn't get it right... There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure what the intention is here. I'm just documenting what it actually does. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Or were you referring to testing strictness generally? |
||
set' | ||
:: Is k A_Setter | ||
:: Is k A_Traversal | ||
=> Optic k is s t a b | ||
-> b -> s -> t | ||
set' o = over' o . const | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks like it might pull in quite a few extra dependencies to
optics-core
. Is that right, and can we avoid it?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, perhaps this is true only for older GHC versions?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks to me like the package is quite careful to avoid excessive dependencies when possible.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For psychological reasons I'd prefer us to not include this dependency.
The cost of not doing so is irrelevant -
Solo
can be copy pasted whereIdentity'
was along with its Applicative instance.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@arybczak Psychological reasons? Why put the compat code here when someone else has already written it there?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, people don't like a lot of deps in "core" packages. Whether it's rational or not is irrelevant.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay ... I'll copy whatever's needed over.