求兼容Control.Lens的Comonad聚焦及Store Comonad位置交互透镜
Absolutely, you can create lenses compatible with Control.Lens to interact with both the focused value (retrieved via extract) and the position (pos) of a Store comonad—including modifying just the focused value without touching other parts of the store. Let’s walk through how to do this.
First, a Quick Recap of Store Comonad Structure
A Store s a wraps two core components:
- A "peek" function
s -> athat maps positions to values - A current position
s(directly accessible via theposfunction)
The focused value returned by extract is simply peek store (pos store)—the value tied to the store’s current position.
1. Lens for the Focused Value (extract Result)
This lens lets you get or update the value at the store’s current position, while leaving the peek function’s behavior for other positions and the current position itself unchanged:
import Control.Lens import Control.Comonad.Store focused :: Lens' (Store s a) a focused = lens extract updateFocus where updateFocus store newVal = store { peek = \pos' -> if pos' == pos store then newVal else peek store pos' }
How it works:
- The getter leverages
extractto pull the current focused value directly. - The setter creates a new store where the peek function returns
newValonly when the position matches the original store’s current position; all other positions retain the original peek behavior.
2. Lens for the Store’s Position (pos)
This one is straightforward—since pos is a direct field of the Store type, we can build a lens to get or set it with minimal code:
position :: Lens' (Store s a) s position = lens pos (\store newPos -> store { pos = newPos })
Example Usage
Let’s put these lenses into action with a concrete example:
-- Create a store: peek adds 10 to any position, current position is 5 (so extract gives 15) myStore :: Store Int Int myStore = store (+10) 5 -- View the focused value view focused myStore -- Returns 15 -- View the current position view position myStore -- Returns 5 -- Modify only the focused value (set it to 20) updatedFocusStore = myStore & focused .~ 20 extract updatedFocusStore -- Returns 20 peek updatedFocusStore 3 -- Still returns 13 (original behavior for other positions) -- Change the position to 7 updatedPosStore = myStore & position .~ 7 extract updatedPosStore -- Returns 17 (10 + 7)
Compatibility with Control.Lens
Since these are proper Lens' values, you can combine them with any of Control.Lens’s combinators. For example:
- Use
over focused (*2)to double the focused value - Chain lenses with other optics (like nested stores or record fields)
- Use
preview focusedif you want aMaybe a(though forStore, this will always returnJustsinceextractis total)
Notes on General Comonads
If you’re curious about a lens that works with any comonad’s extract value, keep in mind that not all comonads support modifying this value—many (like Identity or Env) have immutable focused values. But for Store, which is designed to be navigable and mutable in this way, the focused lens works perfectly.
内容的提问来源于stack exchange,提问作者Chris Penner

