| Copyright | (C) 2013-2016 Edward Kmett, 2015-2016 Artyom |
|---|---|
| License | BSD-style (see the file LICENSE) |
| Safe Haskell | Trustworthy |
| Language | Haskell2010 |
Lens.Micro.Mtl.Internal
Description
This module lets you define your own instances of Zoom and Magnify.
The warning from Lens.Micro.Internal applies to this module as well. Don't export functions that have Zoom or Magnify in their type signatures. If you absolutely need to define an instance (e.g. for internal use), only do it for your own types, because otherwise I might add an instance to one of the microlens packages later and if our instances are different it might lead to subtle bugs.
- type family Zoomed (m :: * -> *) :: * -> * -> *
- class (Zoomed m ~ Zoomed n, MonadState s m, MonadState t n) => Zoom m n s t | m -> s, n -> t, m t -> n, n s -> m where
- type family Magnified (m :: * -> *) :: * -> * -> *
- class (Magnified m ~ Magnified n, MonadReader b m, MonadReader a n) => Magnify m n b a | m -> b, n -> a, m a -> n, n b -> m where
Documentation
type family Zoomed (m :: * -> *) :: * -> * -> * #
This type family is used by Zoom to describe the common effect type.
Instances
| type Zoomed (ListT m) # | |
| type Zoomed (MaybeT m) # | |
| type Zoomed (ExceptT e m) # | |
| type Zoomed (ErrorT e m) # | |
| type Zoomed (StateT s z) # | |
| type Zoomed (StateT s z) # | |
| type Zoomed (WriterT w m) # | |
| type Zoomed (WriterT w m) # | |
| type Zoomed (IdentityT * m) # | |
| type Zoomed (ReaderT * e m) # | |
| type Zoomed (RWST r w s z) # | |
| type Zoomed (RWST r w s z) # | |
class (Zoomed m ~ Zoomed n, MonadState s m, MonadState t n) => Zoom m n s t | m -> s, n -> t, m t -> n, n s -> m where #
Minimal complete definition
Methods
zoom :: LensLike' (Zoomed m c) t s -> m c -> n c infixr 2 #
When you're in a state monad, this function lets you operate on a part of your state. For instance, if your state was a record containing a position field, after zooming position would become your whole state (and when you modify it, the bigger structure would be modified as well).
(Your State / StateT or RWS / RWST can be anywhere in the stack, but you can't use zoom with arbitrary MonadState because it doesn't provide any methods to change the type of the state. See this issue for details.)
For the sake of the example, let's define some types first:
data Position = Position {
_x, _y :: Int }
data Player = Player {
_position :: Position,
... }
data Game = Game {
_player :: Player,
_obstacles :: [Position],
... }
concat <$> mapM makeLenses [''Position, ''Player, ''Game]
Now, here's an action that moves the player north-east:
moveNE ::StateGame () moveNE = do player.position.x+=1 player.position.y+=1
With zoom, you can use player.position to focus just on a part of the state:
moveNE ::StateGame () moveNE = dozoom(player.position) $ do x+=1 y+=1
You can just as well use it for retrieving things out of the state:
getCoords ::StateGame (Int, Int) getCoords =zoom(player.position) ((,)<$>usex<*>usey)
Or more explicitly:
getCoords =zoom(player.position) $ do x' <-usex y' <-usey return (x', y')
When you pass a traversal to zoom, it'll work as a loop. For instance, here we move all obstacles:
moveObstaclesNE ::StateGame () moveObstaclesNE = dozoom(obstacles.each) $ do x+=1 y+=1
If the action returns a result, all results would be combined with <> – the same way they're combined when ^. is passed a traversal. In this example, moveObstaclesNE returns a list of old coordinates of obstacles in addition to moving them:
moveObstaclesNE = do xys <-zoom(obstacles.each) $ do -- Get old coordinates. x' <-usex y' <-usey -- Update them. x.=x' + 1 y.=y' + 1 -- Return a single-element list with old coordinates. return [(x', y')] ...
Instances
| Zoom m n s t => Zoom (ListT m) (ListT n) s t # | |
| Zoom m n s t => Zoom (MaybeT m) (MaybeT n) s t # | |
| Zoom m n s t => Zoom (ExceptT e m) (ExceptT e n) s t # | |
| (Error e, Zoom m n s t) => Zoom (ErrorT e m) (ErrorT e n) s t # | |
| Monad z => Zoom (StateT s z) (StateT t z) s t # | |
| Monad z => Zoom (StateT s z) (StateT t z) s t # | |
| (Monoid w, Zoom m n s t) => Zoom (WriterT w m) (WriterT w n) s t # | |
| (Monoid w, Zoom m n s t) => Zoom (WriterT w m) (WriterT w n) s t # | |
| Zoom m n s t => Zoom (IdentityT * m) (IdentityT * n) s t # | |
| Zoom m n s t => Zoom (ReaderT * e m) (ReaderT * e n) s t # | |
| (Monoid w, Monad z) => Zoom (RWST r w s z) (RWST r w t z) s t # | |
| (Monoid w, Monad z) => Zoom (RWST r w s z) (RWST r w t z) s t # | |
type family Magnified (m :: * -> *) :: * -> * -> * #
This type family is used by Magnify to describe the common effect type.
class (Magnified m ~ Magnified n, MonadReader b m, MonadReader a n) => Magnify m n b a | m -> b, n -> a, m a -> n, n b -> m where #
Minimal complete definition
Methods
magnify :: LensLike' (Magnified m c) a b -> m c -> n c infixr 2 #
This is an equivalent of local which lets you apply a getter to your environment instead of merely applying a function (and it also lets you change the type of the environment).
local:: (r -> r) ->Readerr a ->Readerr amagnify:: Getter r x ->Readerx a ->Readerr a
magnify works with Reader / ReaderT, RWS / RWST, and (->).
Here's an example of magnify being used to work with a part of a bigger config. First, the types:
data URL = URL {
_protocol :: Maybe String,
_path :: String }
data Config = Config {
_base :: URL,
... }
makeLenses ''URL
makeLenses ''Config
Now, let's define a function which returns the base url:
getBase ::ReaderConfig String getBase = do protocol <-fromMaybe"https"<$>view(base.protocol) path <-view(base.path) return (protocol ++ path)
With magnify, we can factor out base:
getBase =magnifybase $ do protocol <-fromMaybe"https"<$>viewprotocol path <-viewpath return (protocol ++ path)