lens-family-core (empty) → 0.0.0
raw patch · 11 files changed
+535/−0 lines, 11 filesdep +basedep +containersdep +transformerssetup-changed
Dependencies added: base, containers, transformers
Files
- CHANGELOG +0/−0
- LICENSE +30/−0
- Setup.lhs +4/−0
- lens-family-core.cabal +50/−0
- src/Lens/Family.hs +129/−0
- src/Lens/Family/Clone.hs +39/−0
- src/Lens/Family/State.hs +5/−0
- src/Lens/Family/State/Lazy.hs +72/−0
- src/Lens/Family/State/Strict.hs +72/−0
- src/Lens/Family/Stock.hs +63/−0
- src/Lens/Family/Unchecked.hs +71/−0
+ CHANGELOG view
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright 2012 Russell O'Connor++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions+are met:++1. Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.++2. Redistributions in binary form must reproduce the above copyright+ notice, this list of conditions and the following disclaimer in the+ documentation and/or other materials provided with the distribution.++3. Neither the name of the author nor the names of his contributors+ may be used to endorse or promote products derived from this software+ without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE+DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN+ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE+POSSIBILITY OF SUCH DAMAGE.
+ Setup.lhs view
@@ -0,0 +1,4 @@+#! /usr/bin/env runhaskell+ +> import Distribution.Simple+> main = defaultMain
+ lens-family-core.cabal view
@@ -0,0 +1,50 @@+name: lens-family-core+category: Data+version: 0.0.0+license: BSD3+cabal-version: >= 1.6+license-file: LICENSE+author: Russell O'Connor+maintainer: Russell O'Connor <roconnor@theorem.ca>+stability: experimental+copyright: Copyright (C) 2012 Russell O'Connor+synopsis: Haskell 98 Lens Families+description: Haskell 98 Lens Families+build-type: Simple+extra-source-files: CHANGELOG+description: This package provide first class(†) functional references.+ In addition to the usual operations of getting, setting and composition, plus integration with the state monad, lens families provide some unique features:+ .+ * Polymorphic updating+ .+ * Cast projection functions to read-only lenses+ .+ * Cast semantic editor combinators to modify-only lenses+ .+ (†) For optimal first-class support use the @lens-family@ package with rank 2 / rank N polymorphism.+ "Lens.Family.Clone" allows for first-class support of lenses for those who require Haskell 98.++source-repository head+ type: darcs+ location: http://r6.ca/lens-family++library+ build-depends:+ base >= 4 && < 5,+ containers >= 0.3 && < 0.5,+ transformers >= 0.2.0 && < 0.4++ exposed-modules:+ Lens.Family.Unchecked+ Lens.Family.Clone+ Lens.Family+ Lens.Family.Stock+ Lens.Family.State.Lazy+ Lens.Family.State.Strict+ Lens.Family.State++ ghc-options: -Wall++ hs-source-dirs:+ src+
+ src/Lens/Family.hs view
@@ -0,0 +1,129 @@+-- | This is the main module for end-users of lens-families.+-- If you are not building your own lenses, but just using top-level defined lenses made by others, this is the only module you need.+-- It provides '^.' for accessing fields and '^=' and '^%=' for setting and modifying fields.+-- Lenses are composed with `Prelude..` from the @Prelude@ and `Prelude.id` is the identity lens.+--+-- /Warning/: Lenses are composed in the opposite order than most lens packages.+-- Lenses in this library enjoy the following identities.+--+-- * @x ^. l1 . l2 === x ^. l1 ^. l2@+--+-- * @l1 . l2 ^%= f === l1 ^%= l2 ^%= f@+--+-- The identity lens behaves as follows.+--+-- * @x ^. id === x@+--+-- * @id ^%= f === f@+--+-- Lenses are implemented in van Laarhoven style. Lenses have type @'Functor' f => (b -> f b) -> a -> f a@ and lens families have type @'Functor' f => (b x -> f (b x')) -> a x -> f (a x')@.+--+-- Remember that lenses and lens families can be used directly for functorial updates.+-- For example, @sndL id@ gives you strength.+--+-- > sndL id :: Functor f => (a, f b) -> f (a, b)+--+-- Here is an example of code that uses the 'Maybe' functor to preserves sharing during update when possible.+--+-- > -- | 'sharedUpdate' returns the *identical* object if the update doesn't change anything.+-- > -- This is useful for preserving sharing.+-- > sharedUpdate :: Eq b => Lens Maybe a b -> (b -> b) -> a -> a+-- > sharedUpdate lens f a = fromMaybe a (lens f' a)+-- > where+-- > f' b | fb == b = Nothing+-- > | otherwise = Just fb+-- > where+-- > fb = f b+--+-- For stock lenses, see "Lens.Family.Stock".+--+-- To build your own lenses, see "Lens.Family.Unchecked".+--+-- References:+--+-- * <http://www.twanvl.nl/blog/haskell/cps-functional-references>+--+-- * <http://r6.ca/blog/20120623T104901Z.html>+--+-- * <http://comonad.com/reader/2012/mirrored-lenses/>+--+-- * <http://conal.net/blog/posts/semantic-editor-combinators>+module Lens.Family+ ( getting, setting+ , (^.)+ , (^%=)+ , (^=)+ -- * Pseudo-imperatives+ , (^+=), (^*=), (^-=), (^/=), (^&&=), (^||=)+ -- * Types+ , GetterFamily, Getter+ , SetterFamily, Setter+ ) where++import Lens.Family.Unchecked (LensFamily)++newtype Getting c a = Getting { unGetting :: c }+instance Functor (Getting c) where+ fmap _ (Getting c) = Getting c++newtype Setting a = Setting { unSetting :: a }+instance Functor Setting where+ fmap f (Setting a) = Setting (f a)++type GetterFamily a a' b b' = LensFamily (Getting b) a a' b b'+type Getter a b = GetterFamily a a b b++type SetterFamily a a' b b' = LensFamily Setting a a' b b'+type Setter a b = SetterFamily a a b b++-- | 'getting' promotes a projection function to a read-only lens.+-- To demote a lens to a projection function, use the section @(^. l)@.+--+-- >>> (3 :+ 4, "example") ^. fstL . getting abs+-- 5.0 :+ 0.0+getting :: (a -> b) -> GetterFamily a a' b b'+getting p _ = Getting . p++-- | 'setting' promotes a \"semantic editor combinator\" to a modify-only lens.+-- To demote a lens to a semantic edit combinator, use the section @(l ^%=)@.+--+-- >>> setting map . fstL ^%= length $ [("The",0),("quick",1),("brown",1),("fox",2)]+-- [(3,0),(5,1),(5,1),(3,2)]+setting :: ((b -> b') -> a -> a') -> SetterFamily a a' b b'+setting s f = Setting . s (unSetting . f)++infixr 8 ^.++-- | Access a field.+(^.) :: a -> GetterFamily a a' b b' -> b+x ^. l = unGetting $ l Getting x++infixr 4 ^%=++-- | Modify a field.+(^%=) :: SetterFamily a a' b b' -> (b -> b') -> a -> a'+l ^%= f = unSetting . l (Setting . f)++-- | Set a field.+infixr 4 ^=++(^=) :: SetterFamily a a' b b' -> b' -> a -> a'+l ^= b = l ^%= const b++infixr 4 ^+=, ^-=, ^*=++(^+=), (^-=), (^*=) :: Num b => Setter a b -> b -> a -> a+f ^+= b = f ^%= (+ b)+f ^-= b = f ^%= subtract b+f ^*= b = f ^%= (* b)++infixr 4 ^/=++(^/=) :: Fractional b => Setter a b -> b -> a -> a+f ^/= b = f ^%= (/ b)++infixr 4 ^&&=, ^||=++(^&&=), (^||=) :: Setter a Bool -> Bool -> a -> a+f ^&&= b = f ^%= (&& b)+f ^||= b = f ^%= (|| b)
+ src/Lens/Family/Clone.hs view
@@ -0,0 +1,39 @@+-- | This module is only provided for Haskell 98 compatibility.+-- If you are able to use @Rank2Types@, I strongly advise you to instead use 'Lens.Family2.Stock.LensFamily' and 'Lens.Family2.Stock.Lens' from the lens-family package instead.+-- +-- 'clone' allows one to circumvent the need for rank 2 types by allowing one to take a universal monomorphic lens instance and rederive a polymorphic instance.+-- When you require a lens family parameter you use the type @'ClonerFamily' a a' b b'@ (or @'Cloner' a b@).+-- Then, inside a @where@ clause, you use 'clone' to create a 'LensFamily' type.+--+-- For example.+--+-- > example :: ClonerFamily a a' b b' -> Example+-- > example l = ... x ^. cl ... cl ^= y ...+-- > where+-- > cl x = clone l x+--+-- /Note/: It is important to eta-expand the definition of 'cl' to avoid the dreaded monomorphism restriction.+--+-- /Note/: Cloning is only need if you use both @Getter@s and @Setter@s in the function.+-- Otherwise you only need to use the monomorphic 'Lens.Family.GetterFamily' \/ 'Lens.Family.Getter' or 'Lens.Family.SetterFamily' \/ 'Lens.Family.Setter'.+module Lens.Family.Clone+ ( clone+ -- * Types+ , LensFamily+ , ClonerFamily, Cloner+ ) where++import Lens.Family.Unchecked (LensFamily)++data Cloning b' b a = Cloning (b' -> a) b+instance Functor (Cloning b' b) where+ fmap f (Cloning g b) = Cloning (f . g) b++type ClonerFamily a a' b b' = LensFamily (Cloning b' b) a a' b b'+type Cloner a b = ClonerFamily a a b b++-- | Converts a universal lens instance back into a polymorphic lens.+clone :: Functor f => ClonerFamily a a' b b' -> LensFamily f a a' b b'+clone univ f a = fmap g (f b)+ where+ Cloning g b = univ (Cloning id) a
+ src/Lens/Family/State.hs view
@@ -0,0 +1,5 @@+module Lens.Family.State + ( module Lens.Family.State.Lazy+ ) where++import Lens.Family.State.Lazy
+ src/Lens/Family/State/Lazy.hs view
@@ -0,0 +1,72 @@+-- | Lenses allow you to use fields of the state of a state monad as if they were variables in an imperative language.+-- 'access' is used to retrieve the value of a variable, and '~=' and '%=' allow you to set and modify a variable.+-- C-style compound assignments are also provided.+module Lens.Family.State.Lazy + ( focus+ , access+ , (%=)+ , (~=)+ , (%%=)+ -- * Compound Assignments+ , (+=), (-=), (*=)+ , (//=)+ , (&&=), (||=)+ -- * Types+ , Focusing+ ) where++import Control.Monad (liftM)+import Control.Monad.Trans.State.Lazy (StateT(..), get, modify)+import Lens.Family (Getter, Setter, (^.), (^%=))+import Lens.Family.Stock (Lens)++{- all these Monad constraints could be weakened to Functor constraints -}++newtype Focusing m c a = Focusing { unFocusing :: m (c, a) }+instance Monad m => Functor (Focusing m c) where+ fmap f (Focusing m) = Focusing (liftM (fmap f) m)++-- | Lift a stateful operation on a field to a stateful operation on the whole state.+-- This is a good way to call a \"subroutine\" that only needs access to part of the state.+focus :: Monad m => Lens (Focusing m c) a b -> StateT b m c -> StateT a m c+focus l m = StateT $ unFocusing . l (Focusing . (runStateT m))++-- | Retrieve a field of the state+access :: Monad m => Getter a b -> StateT a m b+access l = (^. l) `liftM` get++infix 4 %=++-- | Modify a field of the state+(%=) :: Monad m => Setter a b -> (b -> b) -> StateT a m ()+l %= f = modify (l ^%= f)++infix 4 ~=++-- | Set a field of the state+(~=) :: Monad m => Setter a b -> b -> StateT a m ()+l ~= v = l %= const v++infix 4 %%=++-- | Modify a field of the state while returning another value+(%%=) :: Monad m => Lens (Focusing m c) a b -> (b -> (c, b)) -> StateT a m c+l %%= f = focus l (StateT (return . f))++infixr 4 +=, -=, *=++(+=), (-=), (*=) :: (Monad m, Num b) => Setter a b -> b -> StateT a m ()+f += b = f %= (+ b)+f -= b = f %= subtract b+f *= b = f %= (* b)++infixr 4 //=++(//=) :: (Monad m, Fractional b) => Setter a b -> b -> StateT a m ()+f //= b = f %= (/ b)++infixr 4 &&=, ||=++(&&=), (||=) :: Monad m => Setter a Bool -> Bool -> StateT a m ()+f &&= b = f %= (&& b)+f ||= b = f %= (|| b)
+ src/Lens/Family/State/Strict.hs view
@@ -0,0 +1,72 @@+-- | Lenses allow you to use fields of the state of a state monad as if they were variables in an imperative language.+-- 'access' is used to retrieve the value of a variable, and '~=' and '%=' allow you to set and modify a variable.+-- C-style compound assignments are also provided.+module Lens.Family.State.Strict + ( focus+ , access+ , (%=)+ , (~=)+ , (%%=)+ -- * Compound Assignments+ , (+=), (-=), (*=)+ , (//=)+ , (&&=), (||=)+ -- * Types+ , Focusing+ ) where++import Control.Monad (liftM)+import Control.Monad.Trans.State.Strict (StateT(..), get, modify)+import Lens.Family (Getter, Setter, (^.), (^%=))+import Lens.Family.Stock (Lens)++{- all these Monad constraints could be weakened to Functor constraints -}++newtype Focusing m c a = Focusing { unFocusing :: m (c, a) }+instance Monad m => Functor (Focusing m c) where+ fmap f (Focusing m) = Focusing (liftM (fmap f) m)++-- | Lift a stateful operation on a field to a stateful operation on the whole state.+-- This is a good way to call a \"subroutine\" that only needs access to part of the state.+focus :: Monad m => Lens (Focusing m c) a b -> StateT b m c -> StateT a m c+focus l m = StateT $ unFocusing . l (Focusing . (runStateT m))++-- | Retrieve a field of the state+access :: Monad m => Getter a b -> StateT a m b+access l = (^. l) `liftM` get++infix 4 %=++-- | Modify a field of the state+(%=) :: Monad m => Setter a b -> (b -> b) -> StateT a m ()+l %= f = modify (l ^%= f)++infix 4 ~=++-- | Set a field of the state+(~=) :: Monad m => Setter a b -> b -> StateT a m ()+l ~= v = l %= const v++infix 4 %%=++-- | Modify a field of the state while returning another value+(%%=) :: Monad m => Lens (Focusing m c) a b -> (b -> (c, b)) -> StateT a m c+l %%= f = focus l (StateT (return . f))++infixr 4 +=, -=, *=++(+=), (-=), (*=) :: (Monad m, Num b) => Setter a b -> b -> StateT a m ()+f += b = f %= (+ b)+f -= b = f %= subtract b+f *= b = f %= (* b)++infixr 4 //=++(//=) :: (Monad m, Fractional b) => Setter a b -> b -> StateT a m ()+f //= b = f %= (/ b)++infixr 4 &&=, ||=++(&&=), (||=) :: Monad m => Setter a Bool -> Bool -> StateT a m ()+f &&= b = f %= (&& b)+f ||= b = f %= (|| b)
+ src/Lens/Family/Stock.hs view
@@ -0,0 +1,63 @@+-- | This module contains lenses for common structures in Haskell.+-- It also contains the lens combinators 'mergeL' and '***'.+module Lens.Family.Stock+ ( -- * Lens Combinators+ mergeL+ , (***)+ -- * Stock Lenses+ , fstL, sndL+ , funL+ , mapL, intMapL+ , setL, intSetL+ -- * Types+ , LensFamily, Lens+ ) where++import Lens.Family.Unchecked (LensFamily, Lens, mkLens)+import Lens.Family ((^.), (^=))+import Lens.Family.Clone (ClonerFamily, clone)+import qualified Data.Map as Map+import qualified Data.IntMap as IntMap+import qualified Data.Set as Set+import qualified Data.IntSet as IntSet++-- | Given two lens\/getter\/setter families with the same substructure, make a new lens\/getter\/setter on 'Either'.+mergeL :: Functor f => LensFamily f a a' c c' -> LensFamily f b b' c c' -> LensFamily f (Either a b) (Either a' b') c c'+mergeL la _ f (Left a) = Left `fmap` la f a+mergeL _ lb f (Right b) = Right `fmap` lb f b++-- I suspect there is a more clever way to define this function.+-- | Given two lens families, make a new lens on their product.+(***) :: Functor f => ClonerFamily a1 a1' b1 b1' -> ClonerFamily a2 a2' b2 b2' -> LensFamily f (a1, a2) (a1', a2') (b1, b2) (b1', b2')+(***) l1 l2 f (a1, a2) = (\(v'1, v'2) -> (cl1 ^= v'1 $ a1, cl2 ^= v'2 $ a2)) `fmap` f (a1 ^. cl1, a2 ^. cl2)+ where+ cl1 x = clone l1 x+ cl2 x = clone l2 x++-- | Lens on the first element of a pair.+fstL :: Functor f => LensFamily f (a, b) (a', b) a a'+fstL f (a, b) = (\a' -> (a', b)) `fmap` f a++-- | Lens on the second element of a pair.+sndL :: Functor f => LensFamily f (a, b) (a, b') b b'+sndL f (a, b) = (\b' -> (a, b')) `fmap` f b++-- | Lens on a given point of a function.+funL :: (Eq k, Functor f) => k -> Lens f (k -> v) v+funL k f g = (\v' x -> if (k == x) then v' else g x) `fmap` f (g k)++-- | Lens on a given point of a 'Map.Map'.+mapL :: (Ord k, Functor f) => k -> Lens f (Map.Map k v) (Maybe v)+mapL k = mkLens (Map.lookup k) (\m -> maybe (Map.delete k m) (\v' -> Map.insert k v' m))++-- | Lens on a given point of a 'IntMap.IntMap'.+intMapL :: (Functor f) => Int -> Lens f (IntMap.IntMap v) (Maybe v)+intMapL k = mkLens (IntMap.lookup k) (\m -> maybe (IntMap.delete k m) (\v' -> IntMap.insert k v' m))++-- | Lens on a given point of a 'Set.Set'.+setL :: (Ord k, Functor f) => k -> Lens f (Set.Set k) Bool+setL k = mkLens (Set.member k) (\m nv -> if nv then Set.insert k m else Set.delete k m)++-- | Lens on a given point of a 'IntSet.IntSet'.+intSetL :: (Functor f) => Int -> Lens f IntSet.IntSet Bool+intSetL k = mkLens (IntSet.member k) (\m nv -> if nv then IntSet.insert k m else IntSet.delete k m)
+ src/Lens/Family/Unchecked.hs view
@@ -0,0 +1,71 @@+-- | /Caution/: Improper use of this module can lead to unexpected behaviour if the preconditions of the functions are not met.+-- +-- A lens family is created by separating a substructure from the rest of its structure by a functor.+-- How to create a lens family is best illustrated by the common example of a field of a record:+--+-- > data MyRecord a = MyRecord { _myA :: a, _myB :: Int }+-- >+-- > -- The use of type variables a and a' allow for polymorphic updates.+-- > myA :: Functor f => LensFamily f (MyRecord a) (MyRecord a') a a'+-- > myA f (MyRecord a b) = (\a' -> MyRecord a' b) `fmap` (f a)+-- >+-- > -- The field _myB is monomorphic, so we can use a plain Lens type.+-- > -- However, the structure of the function is exactly the same as for LensFamily.+-- > myB :: Functor f => Lens f (MyRecord a) Int+-- > myB f (MyRecord a b) = (\b' -> MyRecord a b') `fmap` (f b)+--+-- By following this template you can safely build your own lenses.+-- To use this template, you do not need anything from this module other than the type synonyms 'LensFamily' and 'Lens', and even they are optional.+-- See the @lens-family-th@ package to generate this code using Template Haskell.+--+-- You can build lenses for more than just fields of records.+-- Any value @lens :: Functor f => LensFamily f a a' b b'@ is well-defined when it satisfies the two van Laarhoven lens laws:+--+-- * @lens Identity === Identity@+--+-- * @+-- lens (composeCoalgebroid f g) === composeCoalgebroid (lens f) (lens g)+-- where+-- composeCoalgebroid :: (Functor f, Functor g) => (b -> f c) -> (a -> g b) -> a -> (Compose g f) c+-- composeCoalgebroid f g a = Compose $ f \`fmap\` g a === id+-- @+--+-- The functions 'mkLens' and 'mkIsoLens' can also be used to construct lenses.+-- The resulting lenses will be well-defined so long as their preconditions are satisfied.+module Lens.Family.Unchecked + ( mkLens+ , mkIsoLens+ -- * Types+ , LensFamily, Lens+ ) where++type LensFamily f a a' b b' = (b -> f b') -> (a -> f a')+type Lens f a b = LensFamily f a a b b++-- | Build a lens from a @getter@ and @setter@ families.+--+-- /Caution/: In order for the generated lens family to be well-defined, you must ensure that the three lens laws hold:+-- +-- * @getter (setter a b) === b@+--+-- * @setter a (getter a) === a@+--+-- * @setter (setter a b1) b2) === setter a b2@+mkLens :: Functor f+ => (a -> b) -- ^ getter+ -> (a -> b' -> a') -- ^ setter+ -> LensFamily f a a' b b'+mkLens getter setter f a = fmap (setter a) (f (getter a))++-- | Build a lens from isomorphism families.+--+-- /Caution/: In order for the generated lens family to be well-defined, you must ensure that the two isomorphism laws hold:+-- +-- * @yin . yang === id@+--+-- * @yang . yin === id@+mkIsoLens :: Functor f + => (a -> b) -- ^ yin+ -> (b' -> a') -- ^ yang+ -> LensFamily f a a' b b'+mkIsoLens getter setter = mkLens getter (const setter)