diff --git a/fmr.cabal b/fmr.cabal
--- a/fmr.cabal
+++ b/fmr.cabal
@@ -1,9 +1,9 @@
 name:          fmr
-version:       0.1
+version:       0.2
 category:      Syntax
 
-synopsis:      Fake monadic records library
-description:   The generalized syntax of abstract monadic records.
+synopsis:      Fields for Monadic Records library
+description:   The generalized, extensible syntax of abstract monadic records.
 
 author:        Andrey Mulik
 maintainer:    <work.a.mulik@gmail.com>
@@ -16,9 +16,21 @@
 build-type:    Simple
 cabal-version: >=1.10
 
+tested-with:
+  -- lts-7.24
+  GHC == 8.0.1,
+  -- lts-9.21
+  GHC == 8.0.2,
+  -- lts-11.22
+  GHC == 8.2.2,
+  -- lts-12.26
+  GHC == 8.4.4,
+  -- lts-18.8
+  GHC == 8.10.6
+
 source-repository head
   type: git
-  location: https://github.com/andreymulik/fake-records
+  location: https://github.com/andreymulik/fmr
 
 ---            _      _____ ______ ______   ___  ______ __   __              ---
 ---           | |    |_   _|| ___ \| ___ \ / _ \ | ___ \\ \ / /              ---
@@ -31,10 +43,13 @@
   default-language: Haskell2010
   hs-source-dirs:   src
   
-  build-depends:    base >= 4.12 && < 5  
+  build-depends:    base >= 4.9 && < 5
   ghc-options:      -Wall -Wcompat
   
   exposed-modules:
     Data.Property
+    Data.MField
+    
+    Data.Field.Observe
     Data.Field
 
diff --git a/src/Data/Field.hs b/src/Data/Field.hs
--- a/src/Data/Field.hs
+++ b/src/Data/Field.hs
@@ -1,190 +1,175 @@
-{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, FlexibleContexts #-}
-{-# LANGUAGE Safe, UndecidableInstances #-}
+{-# LANGUAGE UndecidableSuperClasses, MultiParamTypeClasses, FlexibleInstances #-}
+{-# LANGUAGE Trustworthy, TypeFamilies, FlexibleContexts, PatternSynonyms #-}
 
 {- |
     License     :  BSD-style
     Module      :  Data.Field
-    Copyright   :  (c) Andrey Mulik 2020
+    Copyright   :  (c) Andrey Mulik 2020-2021
     Maintainer  :  work.a.mulik@gmail.com
     
-    @Data.Field@ provides fake field type for record-style operations.
+    @Data.Field@ provides immutable field type for record-style operations.
 -}
 module Data.Field
 (
-  -- * Simple field
-  SField (..), SOField, sfield,
-  
   -- * Field
-  Field (..), OField,
+  Field (..), sfield,
+  GetterFor, SetterFor, ModifierFor, ModifierMFor,
   
-  -- * Observable field
-  Observe (..), observe
+  -- * IsMVar and MonadVar
+  IsMVar (..), MonadVar (..)
 )
 where
 
-import qualified Data.List as L
-
+import Prelude hiding ( (.), id )
 import Data.Property
+import Data.Typeable
 import Data.Functor
+import Data.IORef
+import Data.STRef
+import Data.Kind
 
+import GHC.Conc
+
+import Control.Concurrent.MVar
+import Control.Category
+import Control.Monad.ST
+import Control.Monad
+
 default ()
 
 --------------------------------------------------------------------------------
 
--- | Simple field, which contain only getter and setter.
-data SField m record a = SField
+{- |
+  Normal field, which contain getter, setter and modifier.
+  
+  Since @fmr-0.2@, you can also combine fmr fields using @('.')@ and @'id'@ from
+  the 'Category' class:
+  
+  @
+    outer :: (Monad m) => Field m outer inner
+    inner :: (Monad m) => Field m inner value
+    
+    field :: (Monad m) => Field m outer value
+    field =  outer.inner
+  @
+-}
+data Field m record a = Field
   {
-    -- | Get field value
-    getSField :: !(record -> m a),
-    -- | Set field value
-    setSField :: !(record -> a -> m ())
-  }
-
--- | 'Observe' 'SField'.
-type SOField = Observe SField
-
-instance GetProp    SField record where getRecord = getSField
-instance SetProp    SField record where setRecord = setSField
-instance ModifyProp SField record
-
-instance (SwitchProp Field record) => SwitchProp SField record
-  where
-    switchRecord = switchRecord . toField
-    incRecord    = incRecord . toField
-    decRecord    = decRecord . toField
+    -- | Field getter
+    getField :: !(GetterFor m record a),
+    -- | Field setter
+    setField :: !(SetterFor m record a),
+    -- | Field modifier
+    modifyField :: !(ModifierFor m record a),
+    -- | Monadic field modifier
+    modifyFieldM :: !(ModifierMFor m record a)
+  } deriving ( Typeable )
 
-instance (InsertProp Field record many) => InsertProp SField record many
-  where
-    prependRecord x = prependRecord x . toField
-    appendRecord  x = appendRecord  x . toField
+-- | Getter type.
+type GetterFor m record a = record -> m a
 
-instance (DeleteProp Field record many) => DeleteProp SField record many
-  where
-    deleteRecord x = deleteRecord x . toField
+-- | Setter type.
+type SetterFor m record a = record -> a -> m ()
 
--- | Create 'Field' from getter and setter.
-sfield :: (Monad m) => (record -> m a) -> (record -> a -> m ()) -> Field m record a
-sfield g s = toField (SField g s)
+-- | Modifier type.
+type ModifierFor  m record a = record -> (a -> a) -> m a
 
-toField :: (Monad m) => SField m record a -> Field m record a
-toField field@(SField g s) = Field g s (modifyRecord field)
+-- | Monadic modifier type.
+type ModifierMFor m record a = record -> (a -> m a) -> m a
 
 --------------------------------------------------------------------------------
 
--- | Normal field, which contain getter, setter and modifier.
-data Field m record a = Field
-  {
-    -- | Get field value
-    getField    :: !(record -> m a),
-    -- | Set field value
-    setField    :: !(record -> a -> m ()),
-    -- | Modify field value
-    modifyField :: !(record -> (a -> a) -> m a)
-  }
-
--- | Observable 'Field'.
-type OField = Observe Field
-
-instance GetProp    Field record where getRecord    = getField
-instance SetProp    Field record where setRecord    = setField
-instance ModifyProp Field record where modifyRecord = modifyField
+-- | 'sfield' creates new field from given getter and setter.
+sfield :: (Monad m) => GetterFor m record a -> SetterFor m record a -> Field m record a
+sfield g s = Field g s (\ record  f -> do res <-  f <$> g record; s record res; return res)
+                       (\ record go -> do res <- go =<< g record; s record res; return res)
 
-instance (Integral switch) => SwitchProp Field switch
-  where
-    incRecord field record = void $ modifyRecord field record succ
-    decRecord field record = void $ modifyRecord field record pred
-    
-    switchRecord field record = void . modifyRecord field record . (+) . fromIntegral
+--------------------------------------------------------------------------------
 
-instance {-# INCOHERENT #-} SwitchProp Field Bool
+instance (Monad m) => Category (Field m)
   where
-    incRecord record field = void $ modifyRecord record field not
-    decRecord record field = void $ modifyRecord record field not
+    Field g1 s1 m1 mm1 . Field g2 _ _ _ = Field (g1 <=< g2) s3 m3 mm3
+      where
+        mm3 record   go  = flip mm1  go  =<< g2 record
+        m3  record   f   = flip m1   f   =<< g2 record
+        s3  record value = flip s1 value =<< g2 record
     
-    switchRecord record field n = void $ modifyRecord record field (even n &&)
+    id = Field return (\ _ _ -> return ()) (\ x f -> return (f x)) (flip ($))
 
-instance InsertProp Field record []
-  where
-    appendRecord  x record field = modifyRecord record field (++ [x])
-    prependRecord x record field = modifyRecord record field (x :)
+--------------------------------------------------------------------------------
 
-instance DeleteProp Field record []
+instance FieldGet    Field where getRecord    = getField
+instance FieldSet    Field where setRecord    = setField
+instance FieldModify Field where modifyRecord = modifyField
+instance FieldSwitch Field
   where
-    deleteRecord x record field = modifyRecord record field (L.delete x)
+    switchRecord field record = void .
+      modifyRecord field record . toggle
 
 --------------------------------------------------------------------------------
 
--- | Simple field observer, which can run some handlers after each action.
-data Observe field m record a = Observe
-  {
-    -- | Field to observe.
-    observed :: field m record a,
-    -- | 'getRecord' observer
-    onGet    :: record -> a -> m (),
-    -- | 'setRecord' observer
-    onSet    :: record -> a -> m (),
-    -- | 'modifyRecord' observer
-    onModify :: record -> m ()
-  }
-
--- | Create field with default observers.
-observe :: (Monad m) => field m record a -> Observe field m record a
-observe field =
-  let nothing = \ _ _ -> return ()
-  in  Observe field nothing nothing (\ _ -> return ())
-
-instance (SwitchProp field a) => SwitchProp (Observe field) a
+{- |
+  The 'IsMVar' class provides 'this' field for entire record access.
+  
+  Please note that you cannot create 'IsMVar' and 'MonadVar' instances for some
+  monad separately.
+-}
+class (Monad m, MonadVar m) => IsMVar m var
   where
-    incRecord field record = do
-      incRecord (observed field) record
-      onModify field record
-    
-    decRecord field record = do
-      decRecord (observed field) record
-      onModify field record
+    -- | 'this' is common variable access field.
+    this :: Field m (var a) a
     
-    switchRecord field record n = do
-      switchRecord (observed field) record n
-      onModify field record
+    -- | Create and initialize new mutable variable.
+    var :: a -> m (var a)
 
-instance (GetProp field record) => GetProp (Observe field) record
+instance IsMVar (ST s) (STRef s)
   where
-    getRecord field record = do
-      res <- getRecord (observed field) record
-      onGet field record res
-      return res
+    var  = newSTRef
+    this = Field readSTRef writeSTRef modify' modifyM'
+      where
+        modifyM' ref f = do res <- f =<< readSTRef ref; res <$ writeSTRef ref res
+        modify'  ref f = do res <- f <$> readSTRef ref; res <$ writeSTRef ref res
 
-instance (SetProp field record) => SetProp (Observe field) record
+instance IsMVar IO IORef
   where
-    setRecord field record val = do
-      setRecord (observed field) record val
-      onSet field record val
+    var  = newIORef
+    this = Field readIORef writeIORef modify' modifyM'
+      where
+        modifyM' ref f = do val <- f =<< readIORef ref; writeIORef ref val; return val
+        modify'  ref f = atomicModifyIORef' ref (\ a -> let b = f a in (b, b))
 
-instance (ModifyProp field record) => ModifyProp (Observe field) record
+instance IsMVar IO MVar
   where
-    modifyRecord field record upd = do
-      res <- modifyRecord (observed field) record upd
-      onModify field record
-      return res
+    var  = newMVar
+    this = Field readMVar putMVar modify' modifyM'
+      where
+        modifyM' mvar f = mvar `modifyMVarMasked` \ a -> do b <- f a; return (b, b)
+        modify'  mvar f = mvar `modifyMVar` \ a -> let b = f a in return (b, b)
 
-instance (InsertProp field record many) => InsertProp (Observe field) record many
+instance IsMVar STM TVar
   where
-    prependRecord x field record = do
-      res <- prependRecord x (observed field) record
-      onModify field record
-      return res
-    
-    appendRecord x field record = do
-      res <- appendRecord x (observed field) record
-      onModify field record
-      return res
+    var  = newTVar
+    this = Field readTVar writeTVar modifyTVar modifyMTVar
+      where
+        modifyMTVar tvar f = do res <- f =<< readTVar tvar; res <$ writeTVar tvar res
+        modifyTVar  tvar f = do res <- f <$> readTVar tvar; res <$ writeTVar tvar res
 
-instance (DeleteProp field record many) => DeleteProp (Observe field) record many
-  where
-    deleteRecord x field record = do
-      res <- deleteRecord x (observed field) record
-      onModify field record
-      return res
+--------------------------------------------------------------------------------
 
+{- |
+  'MonadVar' is a class of monads for which defined at least one type of mutable
+  variable.
+  
+  Note that a variable of type @(Var m)@ should be as simple possible for a
+  given monad. I only has to implement the basic operations triad: read,
+  write and update (which don't have to be atomic).
+-}
+class (Monad m, IsMVar m (Var m)) => MonadVar m
+  where
+    -- | @('Var' m)@ is type of mutable variable in monad @m@.
+    type Var m :: Type -> Type
 
+instance MonadVar (ST s) where type Var (ST s) = STRef s
+instance MonadVar IO     where type Var IO     = IORef
+instance MonadVar STM    where type Var STM    = TVar
 
diff --git a/src/Data/Field/Observe.hs b/src/Data/Field/Observe.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Field/Observe.hs
@@ -0,0 +1,80 @@
+{- |
+    License     :  BSD-style
+    Module      :  Data.Field.Observe
+    Copyright   :  (c) Andrey Mulik 2021
+    Maintainer  :  work.a.mulik@gmail.com
+    
+    @Data.Field.Observe@ simple field observer.
+-}
+module Data.Field.Observe
+(
+  -- * Exports
+  module Data.Property,
+  
+  -- * Observable field
+  Observe (..), observe
+)
+where
+
+import Data.Typeable
+import Data.Property
+
+default ()
+
+--------------------------------------------------------------------------------
+
+-- | Simple field observer, which can run some handlers after each action.
+data Observe field m record a = Observe
+  {
+    -- | Field to observe.
+    observed :: field m record a,
+    -- | 'getRecord' observer
+    onGet    :: record -> a -> m (),
+    -- | 'setRecord' observer
+    onSet    :: record -> a -> m (),
+    -- | 'modifyRecord' observer
+    onModify :: record -> m ()
+  }
+  deriving ( Typeable )
+
+-- | Create field with default observers.
+observe :: (Monad m) => field m record a -> Observe field m record a
+observe field =
+  let og = \ _ _ -> return (); om = \ _ -> return (); os = og
+  in  Observe field og os om
+
+--------------------------------------------------------------------------------
+
+instance (FieldSwitch field) => FieldSwitch (Observe field)
+  where
+    switchRecord field record n = do
+      switchRecord (observed field) record n
+      onModify field record
+
+instance (FieldGet field) => FieldGet (Observe field)
+  where
+    getRecord field record = do
+      res <- getRecord (observed field) record
+      onGet field record res
+      return res
+
+instance (FieldSet field) => FieldSet (Observe field)
+  where
+    setRecord field record val = do
+      setRecord (observed field) record val
+      onSet field record val
+
+instance (FieldModify field, FieldGet field) => FieldModify (Observe field)
+  where
+    modifyRecord field record upd = do
+      res <- modifyRecord (observed field) record upd
+      onModify field record
+      return res
+    
+    modifyRecordM field record upd = do
+      res <- modifyRecordM (observed field) record upd
+      onModify field record
+      return res
+
+
+
diff --git a/src/Data/MField.hs b/src/Data/MField.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/MField.hs
@@ -0,0 +1,155 @@
+{-# LANGUAGE Safe, GADTs #-}
+
+{- |
+    License     :  BSD-style
+    Module      :  Data.MField
+    Copyright   :  (c) Andrey Mulik 2020-2021
+    Maintainer  :  work.a.mulik@gmail.com
+    
+    @Data.MField@ provides mutable field type for record-style operations.
+-}
+module Data.MField
+(
+  -- * Exports
+  module Data.Property,
+  module Data.Field,
+  
+  -- * Mutable field
+  MField (..), IsRef (..), MFieldRef, MFieldRep,
+  getter, setter, modifier, modifierM
+)
+where
+
+import Data.Typeable
+import Data.Property
+import Data.Field
+
+import Control.Monad
+
+default ()
+
+--------------------------------------------------------------------------------
+
+{- |
+  @since 0.2
+  
+  'MField' represents field with mutable value and accessors. Unlike fields of
+  type 'Field', 'MField' fields are undesirable (and sometimes impossible) to be
+  stored in the global environment. The dynamic nature of 'MField' means
+  changing accessors for specific records, so accessors do not contain a record
+  argument.
+  
+  'MField' isn't designed for accessing external abstract objects and interfaces,
+  it doesn't give the same freedom as 'Field', but at the same time it allows
+  you to create flexible connections between fields and values without having to
+  reconcile them.
+  
+  'MField' contains a function that takes a record and returns an 'MFieldRef'.
+  
+  Example:
+  
+  @
+    newtype HasField a = HasField {someField :: MFieldRep IO a}
+    
+    field :: MField IO (HasField a) a
+    field =  MField (ref.someField)
+    
+    main :: IO ()
+    main =  do
+      putStrLn "Put some number"
+      record <- fmap HasField $ link =<< var =<< readLn :: IO (HasField Integer)
+      print =<< get field record
+      
+      set record [getter field :~ fmap (* 2)]
+      print =<< get field record
+  @
+-}
+data MField m record a
+  where
+    MField :: (MonadVar m) => (record -> MFieldRef m a) -> MField m record a
+  deriving ( Typeable )
+
+instance FieldGet MField
+  where
+    getRecord (MField field) = join.get this.getRef.field
+
+instance FieldSet MField
+  where
+    setRecord (MField field) record value = do
+      g <- get this.setRef.field $ record; g value
+
+instance FieldModify MField
+  where
+    modifyRecord (MField field) record upd = do
+      m <- get this.modifyRef.field $ record; m upd
+    
+    modifyRecordM (MField field) record go = do
+      mm <- get this.modifyMRef.field $ record; mm go
+
+instance FieldSwitch MField
+  where
+    switchRecord field record = void.modifyRecord field record.toggle
+
+--------------------------------------------------------------------------------
+
+class IsRef ref
+  where
+    -- | Create new reference to the given variable.
+    link :: (MonadVar m) => Var m a -> m (ref m a)
+    
+    -- | Get an associated 'MFieldRef' reference to the given reference.
+    ref :: (MonadVar m) => ref m a -> MFieldRef m a
+
+--------------------------------------------------------------------------------
+
+{- |
+  'MFieldRef' is a structure containing accessors for a specific field of a
+  specific record. As a rule, it makes sense to store 'MFieldRef' in the record
+  to which it refers.
+-}
+data MFieldRef m a = MFieldRef
+  {
+    getRef     :: !(Var m (m a)),
+    setRef     :: !(Var m (a -> m ())),
+    modifyRef  :: !(Var m ((a -> a) -> m a)),
+    modifyMRef :: !(Var m ((a -> m a) -> m a))
+  } deriving ( Typeable )
+
+instance IsRef MFieldRef
+  where
+    ref    = id
+    link x = liftM4 MFieldRef (var (g x)) (var (s x)) (var (m x)) (var (mm x))
+      where
+        Field g s m mm = this
+
+getter :: MField m record a -> Field m record (m a)
+getter (MField f) =
+  let Field g s m mm = this
+  in  Field (g.getRef.f) (s.getRef.f) (m.getRef.f) (mm.getRef.f)
+
+setter :: MField m record a -> Field m record (a -> m ())
+setter (MField f) =
+  let Field g s m mm = this
+  in  Field (g.setRef.f) (s.setRef.f) (m.setRef.f) (mm.setRef.f)
+
+modifier :: MField m record a -> Field m record ((a -> a) -> m a)
+modifier (MField f) =
+  let Field g s m mm = this
+  in  Field (g.modifyRef.f) (s.modifyRef.f) (m.modifyRef.f) (mm.modifyRef.f)
+
+modifierM :: MField m record a -> Field m record ((a -> m a) -> m a)
+modifierM (MField f) =
+  let Field g s m mm = this
+  in  Field (g.modifyMRef.f) (s.modifyMRef.f) (m.modifyMRef.f) (mm.modifyMRef.f)
+
+--------------------------------------------------------------------------------
+
+-- | 'MFieldRep' is a helper type that stores a variable and its accessors.
+data MFieldRep m a = MFieldRep !(Var m a) {-# UNPACK #-} !(MFieldRef m a)
+  deriving ( Typeable )
+
+instance IsRef MFieldRep
+  where
+    link x = MFieldRep x <$> link x
+    ref (MFieldRep _ fr) = fr
+
diff --git a/src/Data/Property.hs b/src/Data/Property.hs
--- a/src/Data/Property.hs
+++ b/src/Data/Property.hs
@@ -1,165 +1,620 @@
-{-# LANGUAGE Safe, DefaultSignatures, GADTs, UndecidableInstances, BangPatterns #-}
-{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies, FlexibleInstances #-}
+{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, UndecidableInstances #-}
+{-# LANGUAGE Safe, GADTs, DefaultSignatures, KindSignatures, DataKinds, CPP #-}
+{-# LANGUAGE PatternSynonyms, ViewPatterns #-}
 
+-- For [ghc-8.0 .. ghc-8.4) support.
+#if __GLASGOW_HASKELL__ < 840
+{-# LANGUAGE TypeInType #-}
+#endif
+
 {- |
     License     :  BSD-style
     Module      :  Data.Property
     Copyright   :  (c) Andrey Mulik 2020
     Maintainer  :  work.a.mulik@gmail.com
     
-    @Data.Property@ provides property type 'Prop' for record-style operations.
+    @Data.Property@ new-style properties.
 -}
 module Data.Property
 (
-  -- * Property
-  Prop (..), get, set, setProp,
+  -- * Generalized properties
+  IsProp (..), PropertyKind, FieldKind, Prop (..),
   
-  -- ** Get
-  GetProp (..),
+  -- ** Basic properties
+  FieldGet (..), get, gets',
+  FieldSet (..), set, sets',
   
-  -- ** Set
-  SetProp (..),
+  -- *** Set properties
+  pattern (:=), pattern (::=), pattern (:=$), pattern (::=$),
   
-  -- ** Modify
-  ModifyProp (..), InsertProp (..), DeleteProp (..), SwitchProp (..)
+  -- *** Monadic set properties
+  pattern (:<=), pattern (:<=$), pattern (:=<), pattern (:=<$),
+  
+  -- ** Modify properties
+  FieldModify (..),
+  
+  -- *** Modify properties
+  pattern (:~), pattern (:~$), pattern (::~), pattern (::~$),
+  
+  -- *** Monadic modify properties
+  pattern (:<~), pattern (:<~$), pattern (:~<), pattern (:~<$),
+  
+  -- ** Switch properties
+  IsSwitch (..), FieldSwitch (..), switch, incr, decr
 )
 where
 
-import Data.Functor
+import Data.Typeable
+import Data.Kind
 
+import Control.Monad
+
 default ()
 
 --------------------------------------------------------------------------------
 
--- | Property representation
+{- Generalized property. -}
+
+{- |
+  @since 0.2
+  'Prop' is new, generalized and extensible property type (existential), which
+  may contain any 'IsProp' value.
+-}
 data Prop m field record
   where
-    -- | Increase property value (switch flag, increment, etc.).
-    Incr :: (Monad m, SwitchProp field a) =>
-      field m record a -> Prop m field record
-    
-    -- | Decrease property value (switch flag, decrement, etc.).
-    Decr :: (Monad m, SwitchProp field a) =>
-      field m record a -> Prop m field record
-    
-    -- | Increase/decrease value many times.
-    Switch :: (Monad m, SwitchProp field a) =>
-      field m record a -> Int -> Prop m field record
+    Prop :: (Monad m, IsProp prop) => prop m field record -> Prop m field record
+  deriving ( Typeable )
+
+{- |
+  @since 0.2
+  'IsProp' is a property class that allows you to extend @fmr@ syntax. Now you
+  can create new property types and use it with existing in 'set' list of
+  actions.
+-}
+class IsProp (prop :: PropertyKind)
+  where
+    -- | @performProp record prop @ performs an action on @record@ using @prop@.
+    performProp :: (Monad m) => record -> prop m field record -> m ()
+
+instance IsProp SetProp
+  where
+    performProp record (SetRecordPropM field   kl) = setRecords field record =<< kl record
+    performProp record (SetRecordProp  field    f) = setRecords field record (f record)
+    performProp record (SetPropM       field mval) = setRecords field record =<< mval
+    performProp record (SetProp        field  val) = setRecords field record val
+
+setRecords :: (Monad m, FieldSet field) => [field m record a] -> record -> a -> m ()
+setRecords fields record val = forM_ fields $ \ field -> setRecord field record val
+
+instance IsProp ModifyProp
+  where
+    performProp record (Modify      field f) = () <$ modifyRecords  field record (f record)
+    performProp record (ModifyM     field f) = () <$ modifyRecordsM field record (f record)
+    performProp record (ModifyProp  field f) = () <$ modifyRecords  field record f
+    performProp record (ModifyPropM field f) = () <$ modifyRecordsM field record f
+
+modifyRecords :: (Monad m, FieldModify field) =>
+  [field m record b] -> record -> (b -> b) -> m ()
+modifyRecords fields record f = fields `forM_` \ field -> modifyRecord field record f
+
+modifyRecordsM :: (Monad m, FieldModify field, FieldGet field) =>
+  [field m record b] -> record -> (b -> m b) -> m ()
+modifyRecordsM fields record f = fields `forM_` \ field -> modifyRecordM field record f
+
+instance IsProp SwitchProp
+  where
+    performProp record (SwitchProp n field) = switchRecord field record n
+
+--------------------------------------------------------------------------------
+
+-- | @since 0.2 Service kind synonym.
+type FieldKind = (Type -> Type) -> Type -> Type -> Type
+
+-- | @since 0.2 Service kind synonym.
+type PropertyKind = (Type -> Type) -> FieldKind -> Type -> Type
+
+--------------------------------------------------------------------------------
+
+{- fmr classes. -}
+
+-- | @since 0.2 Property getter class.
+class FieldGet field
+  where
+    -- | @'getRecord' field record@ return @record@'s value using @field@.
+    getRecord :: (Monad m) => field m record a -> record -> m a
+
+-- | @since 0.2 Property setter class.
+class FieldSet field
+  where
+    -- | @'setRecord' field record value@ sets new @record@ @value@.
+    setRecord :: (Monad m) => field m record a -> record -> a -> m ()
+
+{- |
+  @since 0.2
+  Property modifier class.
+  
+  Note that 'FieldModifier' doesn't go well with write-only fields, because
+  'modifyRecord' returns new value, and 'modifyRecordM' also assumes the
+  possibility of old value \"leaking\" (hence the 'FieldGet' constraint is
+  imposed on it).
+-}
+class (FieldSet field) => FieldModify field
+  where
+    {- |
+      @'modifyRecord' field record upd@ modifies @record@ @field@ using @upd@.
+      Returns new value.
+    -}
+    default modifyRecord :: (Monad m, FieldGet field) =>
+      field m record a -> record -> (a -> a) -> m a
+    modifyRecord :: (Monad m) => field m record a -> record -> (a -> a) -> m a
+    modifyRecord field record f = do
+      val <- f <$> get field record
+      setRecord field record val
+      return val
     
-    -- | @field ':=' val@ sets new value @val@ to record.
-    (:=)  :: (Monad m, SetProp field record) =>
-      field m record a -> a -> Prop m field record
+    {- |
+      @'modifyRecordM' field record upd@ modifies @record@ @field@ using @upd@.
+      Note that assumes the possibility of old value \"leaking\", e.g.:
+      
+      @
+        -- get value using 'modifyRecordM'
+        getLeak = do
+          -- Some read-only fields
+          x <- newWriteOnly
+          y <- 'var' Nothing
+          -- write current value to y and do not modify.
+          modifyRecordM this x (\ val -> do set [this := Just val]; return val)
+          -- leaking: return current value of "write-only" record
+          get this y
+      @
+      
+      So you cannot use it for write-only fields.
+    -}
+    modifyRecordM :: (Monad m, FieldGet field) =>
+      field m record a -> record -> (a -> m a) -> m a
+    modifyRecordM field record f = do
+      val <- f =<< get field record
+      setRecord field record val
+      return val
+
+{- |
+  Switch property modifier.
+  
+  Note that 'FieldSwitch' is designed for deterministic switches with a
+  pre-known set of states and order of transitions between them, without
+  branches. If you need more complex behavior, use 'FieldModify'.
+-}
+class FieldSwitch field
+  where
+    -- | Repeated increment or decrement.
+    switchRecord :: (Monad m, IsSwitch a) => field m record a -> record -> Int -> m ()
+
+--------------------------------------------------------------------------------
+
+{- fmr properties. -}
+
+{- |
+  @since 0.2
+  'SetProp' is a service type used to set field values.
+  See @(':=')@, @(':=$')@, @('::=')@, @('::=$')@, @(':<=')@, @(':<=$')@,
+  @(':=<')@ and @(':=<$')@ patterns.
+-}
+data SetProp m field record
+  where
+    -- | 'SetProp' corresponds to @(':=$')@ and @(':=')@.
+    SetProp :: (FieldSet field) =>
+      [field m record a] -> a -> SetProp m field record
     
-    -- | @field '::=' upd@ - updates value using @upd@.
-    (::=) :: (Monad m, SetProp field record) =>
-      field m record a -> (record -> a) -> Prop m field record
+    -- | 'SetPropM' corresponds to @('::=$')@ and @('::=')@.
+    SetPropM :: (FieldSet field) =>
+      [field m record a] -> m a -> SetProp m field record
     
-    -- | @field ':~' upd@ updates value using @upd@.
-    (:~)  :: (Monad m, ModifyProp field record) =>
-      field m record a -> (a -> a) -> Prop m field record
+    -- | 'SetRecordProp' corresponds to @(':<=$')@ and @(':<=')@.
+    SetRecordProp :: (FieldSet field) =>
+      [field m record a] -> (record -> a) -> SetProp m field record
     
-    -- | @field '::=' upd@ - updates value using @upd@.
-    (::~) :: (Monad m, ModifyProp field record) =>
-      field m record a -> (record -> a -> a) -> Prop m field record
+    -- | 'SetRecordPropM' corresponds to @(':=<$')@ and @(':=<')@.
+    SetRecordPropM :: (FieldSet field) =>
+      [field m record a] -> (record -> m a) -> SetProp m field record
+  deriving ( Typeable )
+
+{- |
+  @since 0.2
+  'ModifyProp' is a service type used to modify field values.
+  See @(':~')@, @(':~$')@, @(':<~')@, @(':<~$')@, @('::~')@, @('::~$')@,
+  @(':~<')@, @(':~<$')@ patterns.
+-}
+data ModifyProp m field record
+  where
+    -- | 'FieldModify' constructor corresponds to @(':~$')@ and @(':~')@.
+    ModifyProp :: (FieldModify field) =>
+      [field m record a] -> (a -> a) -> ModifyProp m field record
     
-    -- | @field ':=+' val@ appends @val@ to @record@ value.
-    (:=+) :: (Monad m, InsertProp field record many) =>
-      field m record (many a) -> a -> Prop m field record
+    -- | 'FieldModify' constructor corresponds to @(':<~$')@ and @(':<~')@.
+    ModifyPropM :: (FieldModify field, FieldGet field) =>
+      [field m record a] -> (a -> m a) -> ModifyProp m field record
     
-    -- | @val ':=+' field@ prepends @val@ to @record@ value.
-    (:+=) :: (Monad m, InsertProp field record many) =>
-      a -> field m record (many a) -> Prop m field record
+    -- | 'Modify' constructor corresponds to @('::~$')@ and @('::~')@.
+    Modify :: (FieldModify field) =>
+      [field m record a] -> (record -> a -> a) -> ModifyProp m field record
     
-    -- | @field ':~=' val@ removes @val@ from @record@ value
-    (:~=) :: (Monad m, DeleteProp field record many, Eq a) =>
-      field m record (many a) -> a -> Prop m field record
+    -- | 'ModifyM' constructor corresponds to @(':~<$')@ and @(':~<')@.
+    ModifyM :: (FieldModify field, FieldGet field) =>
+      [field m record a] -> (record -> a -> m a) -> ModifyProp m field record
+  deriving ( Typeable )
 
+{- |
+  @since 0.2
+  'SwitchProp' is a service type used to update record values, see 'switch',
+  'incr' and 'decr'.
+-}
+data SwitchProp m field record
+  where
+    -- | Switch field, see 'switch', 'incr' and 'decr'.
+    SwitchProp :: (Monad m, FieldSwitch field, IsSwitch a) =>
+      Int -> field m record a -> SwitchProp m field record
+  deriving ( Typeable )
+
 --------------------------------------------------------------------------------
 
--- | 'getRecord' shortcut.
-get :: (Monad m, GetProp field record) => field m record a -> record -> m a
-get =  getRecord
+{- fmr pure setters. -}
 
--- | 'setProp' shortcut.
-set :: (Monad m) => record -> [Prop m field record] -> m ()
-set =  setProp
+{- |
+  Pure value setter. @set record [field := value]@ set @value@ to @record@'s
+  @field@.
+-}
+pattern (:=) ::
+  (
+    Typeable m, Typeable field, Typeable record,
+    Monad m, FieldSet field
+  ) => field m record a -> a -> Prop m field record
+pattern field := val = [field] :=$ val
 
--- | @setRecord record props@ changes @record@ value using @props@ properties.
-setProp :: (Monad m) => record -> [Prop m field record] -> m ()
-setProp record = mapM_ $ \ prop -> case prop of
-  Incr    field   -> incRecord    field record
-  Decr    field   -> decRecord    field record
-  Switch  field n -> switchRecord field record n
+{- |
+  Pure value setter with @record@. @set record [field ::= f]@ set @f record@ to
+  @record@'s @field@.
   
-  field ::=   upd -> setRecord field record (upd record)
-  field :=    val -> setRecord field record val
-  field ::~   upd -> void $ modifyRecord field record (upd record)
-  field :~    upd -> void $ modifyRecord field record upd
+  @
+    set record [field ::= const val] === set record [field := val]
+  @
+-}
+pattern (::=) ::
+  (
+    Typeable m, Typeable field, Typeable record,
+    Monad m, FieldSet field
+  ) => field m record a -> (record -> a) -> Prop m field record
+pattern field ::= f = [field] ::=$ f
+
+{- |
+  @since 0.2
+  Pure group setter. @set record [fields :=$ value]@ set @value@ to @record@'s
+  some @fields@.
   
-  field :=+   val -> void $ prependRecord val field record
-  val   :+= field -> void $ appendRecord  val field record
-  field :~=   val -> void $ deleteRecord  val field record
+  @
+    set record [[field] :=$ value] === set record [field := value]
+  @
+-}
+pattern (:=$) ::
+  (
+    Typeable m, Typeable field, Typeable record,
+    Monad m, FieldSet field
+  ) => [field m record a] -> a -> Prop m field record
+pattern field :=$ val <- (cast -> Just (SetProp field val))
+  where
+    (:=$) = Prop ... SetProp
 
+{- |
+  @since 0.2
+  Pure group setter with @record@. @set record [fields ::=$ f]@ set @f record@
+  to @record@'s some @fields@.
+  
+  @
+    set record [[field] ::=$ f] === set record [field ::= f]
+    set record [fields ::=$ const val] === set record [fields :=$ val]
+  @
+-}
+pattern (::=$) ::
+  (
+    Typeable m, Typeable field, Typeable record, Monad m, FieldSet field
+  ) => [field m record a] -> (record -> a) -> Prop m field record
+pattern field ::=$ f <- (cast -> Just (SetRecordProp field f))
+  where
+    (::=$) = Prop ... SetRecordProp
+
 --------------------------------------------------------------------------------
 
--- | Property getter.
-class GetProp field record
+{- fmr pure updaters. -}
+
+{- |
+  Pure value modifier. @set record [field :~ f]@ modify value of @record@'s
+  @field@ using @f@ function.
+  
+  @
+    set record [field :~ const val] === set record [field := val]
+  @
+-}
+pattern (:~) ::
+  (
+    Typeable m, Typeable field, Typeable record,
+    Monad m, FieldModify field
+  ) => field m record a -> (a -> a) -> Prop m field record
+pattern field :~ f = [field] :~$ f
+
+{- |
+  Pure value modifier with @record@. @set record [field ::~ f]@ modify value of
+  @record@'s @field@ using @f record@ function.
+  
+  @
+    set record [field ::~ const f] === set record [field :~ f]
+  @
+-}
+pattern (::~) ::
+  (
+    Typeable m, Typeable field, Typeable record,
+    Monad m, FieldModify field
+  ) => field m record a -> (record -> a -> a) -> Prop m field record
+pattern field ::~ f = [field] ::~$ f
+
+{- |
+  @since 0.2
+  Pure group modifier. @set record [fields :~$ f]@ modify values of @record@'s
+  @fields@ using @f@ function.
+  
+  @
+    set record [[field] :~$ val] === set record [field :~ val]
+    set record [fields :~$ const val] === set record [field :=$ val]
+  @
+-}
+pattern (:~$) ::
+  (
+    Typeable m, Typeable field, Typeable record,
+    Monad m, FieldModify field
+  ) => [field m record a] -> (a -> a) -> Prop m field record
+pattern field :~$ f <- (cast -> Just (ModifyProp field f))
   where
-    -- | @'getRecord' field record@ return @record@'s value using @field@.
-    getRecord :: (Monad m) => field m record a -> record -> m a
+    (:~$) = Prop ... ModifyProp
 
--- | Property setter.
-class SetProp field record
+{- |
+  @since 0.2
+  Pure group modifier with @record@.
+  @set record [fields ::~$ f]@ modify values of @record@'s @fields@ using
+  @f record@ function.
+  
+  @
+    set record [[field] ::~$ f] === set record [field ::~ f]
+    set record [fields ::~$ const f] === set record [field :~$ f]
+  @
+-}
+pattern (::~$) ::
+  (
+    Typeable m, Typeable field, Typeable record,
+    Monad m, FieldModify field
+  ) => [field m record a] -> (record -> a -> a) -> Prop m field record
+pattern field ::~$ f <- (cast -> Just (Modify field f))
   where
-    -- | @'setRecord' field record value@ sets new @record@ @value@.
-    setRecord :: (Monad m) => field m record a -> record -> a -> m ()
+    (::~$) = Prop ... Modify
 
--- | Property modifier.
-class ModifyProp field record
+--------------------------------------------------------------------------------
+
+{- fmr monadic setters. -}
+
+{- |
+  @since 0.2
+  Monadic value setter. @set record [field :<= mvalue]@ set result of @mvalue@
+  to @record@'s @field@. Note that the @mvalue@ is evaluated every time a
+  @field@ value is assigned.
+  
+  @
+    set record [field :<= return val] === set record [field := val]
+    set record [field :<= mval] === do val <- mval; set record [field :<= val]
+  @
+-}
+pattern (:<=) ::
+  (
+    Typeable m, Typeable field, Typeable record,
+    Monad m, FieldSet field
+  ) => field m record a -> m a -> Prop m field record
+pattern field :<= mval = [field] :<=$ mval
+
+{- |
+  @since 0.2
+  Monadic value setter with @record@. @set record [field :=< mvalue]@ set result
+  of @mvalue record@ to @record@'s @field@. Note that the @mvalue@ is evaluated
+  every time a @field@ value is assigned.
+  
+  @
+    set record [field :=< const val] === set record [field :<= val]
+    set record [field :=< f] === do val <- f record; set record [field := val]
+  @
+-}
+pattern (:=<) ::
+  (
+    Typeable m, Typeable field, Typeable record,
+    Monad m, FieldSet field
+  ) => field m record a -> (record -> m a) -> Prop m field record
+pattern field :=< f = [field] :=<$ f
+
+{- |
+  @since 0.2
+  Monadic group setter. @set record [fields :<=$ mvalue]@ set result of @mvalue@
+  to @record@'s @fields@. Note that @mvalue@ is evaluated only once, on the
+  first assignment. Thus, the values of all the listed fields will be identical.
+  
+  @
+    set record [[field] :<=$ const f] === set record [field :<= val]
+    set record [fields :<=$ mval] === do val <- mval; set record [fields :<=$ val]
+  @
+-}
+pattern (:<=$) ::
+  (
+    Typeable m, Typeable field, Typeable record,
+    Monad m, FieldSet field
+  ) => [field m record a] -> m a -> Prop m field record
+pattern field :<=$ mval <- (cast -> Just (SetPropM field mval))
   where
-    -- | @'modifyRecord' field record upd@ modifies @record@ @field@ using @upd@.
-    default modifyRecord :: (Monad m, GetProp field record, SetProp field record) =>
-      field m record a -> record -> (a -> a) -> m a
-    modifyRecord :: (Monad m) => field m record a -> record -> (a -> a) -> m a
-    modifyRecord field record f = do
-      old <- get field record
-      let new = f old
-      setRecord field record new
-      return new
+    (:<=$) = Prop ... SetPropM
 
+{- |
+  @since 0.2
+  Monadic group setter with @record@. @set record [fields :=<$ f]@ set result of
+  @f record@ to @record@'s @fields@. Note that @f record@ is evaluated only
+  once, on the first assignment. Thus, the values of all the listed fields will
+  be identical.
+  
+  @
+    set record [[field] :=<$ f] === set record [field :=< val]
+    set record [fields :=<$ const val] = set record [fields :=$ val]
+    set record [fields :=<$ f] === do val <- f record; set record [fields :=$ val]
+  @
+-}
+pattern (:=<$) ::
+  (
+    Typeable m, Typeable field, Typeable record,
+    Monad m, FieldSet field
+  ) => [field m record a] -> (record -> m a) -> Prop m field record
+pattern field :=<$ f <- (cast -> Just (SetRecordPropM field f))
+  where
+    (:=<$) = Prop ... SetRecordPropM
+
 --------------------------------------------------------------------------------
 
--- | Switch property modifier.
-class SwitchProp field a
+{- fmr monadic updaters. -}
+
+{- |
+  @since 0.2
+  Monadic value modifier. @set record [field :<~ f]@ modifies value of
+  @record@'s @field@ using @f@ procedure. Note that the @mvalue@ is called every
+  time a @field@ value is assigned.
+  
+  @
+    set record [field :<~ return val] === set record [fields := val]
+  @
+-}
+pattern (:<~) ::
+  (
+    Typeable m, Typeable field, Typeable record, Monad m,
+    FieldModify field, FieldGet field
+  ) => field m record a -> (a -> m a) -> Prop m field record
+pattern field :<~ f = [field] :<~$ f
+
+{- |
+  @since 0.2
+  Monadic value modifier with @record@. @set record [field :<~ f]@ modifies
+  value of @record@'s @field@ using @f record@ procedure. Note that the
+  @f record@ is called every time a @field@ value is assigned.
+  
+  @
+    set record [field :~< const f] === set record [fields :<~ f]
+  @
+-}
+pattern (:~<) ::
+  (
+    Typeable m, Typeable field, Typeable record,
+    Monad m, FieldModify field, FieldGet field
+  ) => field m record a -> (record -> a -> m a) -> Prop m field record
+pattern field :~< f = [field] :~<$ f
+
+{- |
+  @since 0.2
+  Monadic group modifier. @set record [fields :<~$ f]@ modifies values of
+  @record@'s @fields@ using @f@ procedure.
+  
+  @
+    set record [[field] :<~$ f] === set record [field :<~ f]
+    set record [fields :<~$ const mval] === set record [field :<=$ mval]
+  @
+-}
+pattern (:<~$) ::
+  (
+    Typeable m, Typeable field, Typeable record,
+    Monad m, FieldModify field, FieldGet field
+  ) => [field m record a] -> (a -> m a) -> Prop m field record
+pattern field :<~$ f <- (cast -> Just (ModifyPropM field f))
   where
-    -- | Generalized increment, same as @switchRecord@.
-    incRecord :: (Monad m) => field m record a -> record -> m ()
-    
-    -- | Generalized decrement.
-    decRecord :: (Monad m) => field m record a -> record -> m ()
-    
+    (:<~$) = Prop ... ModifyPropM
+
+{- |
+  @since 0.2
+  Monadic group modifier with @record@. @set record [fields :~<$ f]@ modifies
+  values of @record@'s @fields@ using @f record@ procedure. Note that the
+  @f record@ is called every time a @field@ value is assigned.
+  
+  @
+    set record [field :~<$ const f] === set record [fields :<~$ f]
+  @
+-}
+pattern (:~<$) ::
+  (
+    Typeable m, Typeable field, Typeable record,
+    Monad m, FieldModify field, FieldGet field
+  ) => [field m record a] -> (record -> a -> m a) -> Prop m field record
+pattern field :~<$ f <- (cast -> Just (ModifyM field f))
+  where
+    (:~<$) = Prop ... ModifyM
+
+--------------------------------------------------------------------------------
+
+-- | Service class for switchable types.
+class IsSwitch switch
+  where
     {- |
-      Increment/decrement many times.
+      @'toggle' s n@ "toggles" the state represented by the value @s@ by @n@
+      positions, for example:
       
-      > decRecord field record = switchRecord field record (-1)
-      > incRecord field record = switchRecord field record 1
+      @
+        toggle n False = even n
+        toggle n  True = odd  n
+        toggle n  1234 = 1239 + n
+      @
     -}
-    switchRecord :: (Monad m) => field m record a -> record -> Int -> m ()
+    toggle :: Int -> switch -> switch
 
--- | Prepend/append modifier.
-class InsertProp field record many
+instance IsSwitch Bool
   where
-    -- | Prepends new element to existing value.
-    prependRecord :: (Monad m) => a -> field m record (many a) -> record -> m (many a)
-    
-    -- | Appends new element to existing value.
-    appendRecord :: (Monad m) => a -> field m record (many a) -> record -> m (many a)
+    toggle n False = even n
+    toggle n  True = odd  n
 
--- | Delete modifier.
-class DeleteProp field record many
-  where
-    -- | Delete element from value (if any).
-    deleteRecord :: (Monad m, Eq a) => a -> field m record (many a) -> record -> m (many a)
+instance (Integral i) => IsSwitch i where toggle n i = fromIntegral n + i
 
+--------------------------------------------------------------------------------
 
+-- | The 'get' function reads current value of a field.
+get :: (Monad m, FieldGet field) => field m record a -> record -> m a
+get =  getRecord
+
+-- | @'gets'' fields record@ returns list of @record@ @fields@ values.
+gets' :: (Monad m, FieldGet field) => record -> [field m record a] -> m [a]
+gets' =  mapM . flip getRecord
+
+{- |
+  'set' is the main function in @fmr@, which allows you to describe changing the
+  value of a record as a sequence of operations on its fields, e.g.
+-}
+set :: (Monad m) => record -> [Prop m field record] -> m ()
+set record = mapM_ $ \ (Prop prop) -> performProp record prop
+
+-- | Just synonym for 'set'.
+sets' :: (Monad m) => record -> [Prop m field record] -> m ()
+sets' =  set
+
+-- | 'switch' changes the value by n steps.
+switch :: (Monad m, FieldSwitch field, IsSwitch a) =>
+  field m record a -> Int -> Prop m field record
+switch field n = Prop (SwitchProp n field)
+
+-- | @'incr' field@ is same as @switch field 1@.
+incr :: (Monad m, FieldSwitch field, IsSwitch a) =>
+  field m record a -> Prop m field record
+incr =  Prop . SwitchProp 1
+
+-- | @'decr' field@ is same as @switch field (-1)@.
+decr :: (Monad m, FieldSwitch field, IsSwitch a) =>
+  field m record a -> Prop m field record
+decr =  Prop . SwitchProp (-1)
+
+--------------------------------------------------------------------------------
+
+-- | @sdp@ @(.)@-like combinator.
+(...) :: (c -> d) -> (a -> b -> c) -> a -> b -> d
+(...) =  (.) . (.)
 
