packages feed

monad-codec (empty) → 0.0.1

raw patch · 4 files changed

+225/−0 lines, 4 filesdep +basedep +containersdep +lenssetup-changed

Dependencies added: base, containers, lens, mtl

Files

+ Control/Monad/Codec.hs view
@@ -0,0 +1,161 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE RankNTypes #-}++-- | The Codec monad provides functions for encoding and decoding+-- complex data structures with unique integer numbers.  In the+-- simplest case the entire sturecture can be transformed to unique+-- atom (see 'example1' below).  When it is not sufficient to encode+-- the input object with one codec, more complex codec structure can+-- be used (see 'example2' below).  In order to simplify codec+-- manipulations the library relies on a 'lens' package  which provides+-- lenses for typical data types.+--+-- Example:+--+-- > example1 = evalCodec empty $ do+-- >     let xs = "abcabd"+-- >     ys <- mapM (encode id) xs+-- >     zs <- mapM (decode id) ys+-- >     return $ zip zs ys+--+-- >>> example1+-- >>> [('a',0),('b',1),('c',2),('a',0),('b',1),('d',3)]+--+-- > example2 = evalCodec (empty, empty) $ do+-- >     let xs = zip "abcabd" [1, 34342, 5435, 34342, 124, 1]+-- >     ys <- forM xs $ \(x, y) ->+-- >         (,) <$> encode _1 x <*> encode _2 y+-- >     zs <- forM ys $ \(i, j) -> +-- >         (,) <$> decode _1 i <*> decode _2 j+-- >     return (zs, ys)+--+-- >>> fst example2+-- >>> [('a',1),('b',34342),('c',5435),('a',34342),('b',124),('d',1)]+-- >>> snd example2+-- >>> [(0,0),(1,1),(2,2),(0,1),(1,3),(3,0)]++module Control.Monad.Codec+( Codec ()+, AtomCodec (..)+, empty+, AtomLens+, maybeEncode+, encode+, encode'+, maybeDecode+, decode++, runCodec+, evalCodec+, execCodec+) where++import Control.Applicative (Applicative, (<$>))+import Control.Lens (Simple, Lens, view, set)+import qualified Control.Monad.State as S+import qualified Data.Map as M+import qualified Data.IntMap as I++-- | A Codec monad preserves mappings between objects and respective+-- codec components.+newtype Codec c a = Codec (S.State c a)+    deriving (Functor, Applicative, Monad)++-- | Get codec structure from the Codec monad.+getCodec :: Codec c c+getCodec = Codec S.get+{-# INLINE getCodec #-}++-- | Set codec structure within the Codec monad.+setCodec :: c -> Codec c ()+setCodec codec = Codec (S.put codec)+{-# INLINE setCodec #-}++-- | Atomic Codec component, which represents to and fro mapping+-- between 'a' objects and unique intergers.+data AtomCodec a = AtomCodec+    { to    :: !(M.Map a Int)+    , from  :: !(I.IntMap a) }++-- | Empty codec component.+empty :: AtomCodec a+empty = AtomCodec M.empty I.empty++-- | Update the map with the given element and increase the counter.  If the+-- element has not been previously in the map it will be assigned a new unique+-- integer number.+updateMap :: Ord a => M.Map a Int -> a -> M.Map a Int+updateMap mp x =+  case M.lookup x mp of+    Just _k -> mp+    Nothing -> M.insert x n mp+  where+    !n = M.size mp++-- | Just a type synonym for a lens between codec and codec component.+type AtomLens c a = Simple Lens c (AtomCodec a)++-- | Encode the object with codec component identified by the lens.+-- Return Nothing if the object is not present in the atomic+-- codec component.+maybeEncode :: Ord a => AtomLens c a -> a -> Codec c (Maybe Int)+maybeEncode lens x = +    M.lookup x . to . view lens <$> getCodec++-- | Encode the object with codec component identified by the lens.+encode :: Ord a => AtomLens c a -> a -> Codec c Int+encode lens x = do+    codec <- getCodec+    let atomCodec = view lens codec+        m' = updateMap (to atomCodec) x+        y  = m' M.! x+        r' = I.insert y x (from atomCodec)+        codec' = set lens (AtomCodec m' r') codec+    setCodec codec'+    return y++-- | Version of encode which doesn't update the return componenent+-- of the atom codec.  It is useful when we know that particular+-- value (e.g. value of a condition observation) won't be decoded+-- afterwards so there is no need to store it and waste memory.+encode' :: Ord a => AtomLens c a -> a -> Codec c Int+encode' lens x = do+    codec <- getCodec+    let atomCodec = view lens codec+        m' = updateMap (to atomCodec) x+        y  = m' M.! x+        codec' = set lens (atomCodec { to = m' }) codec+    setCodec codec'+    return y++-- | Decode the number with codec component identified by the lens.+-- Return Nothing if the object is not present in the atomic+-- codec component.+maybeDecode :: Ord a => AtomLens c a -> Int -> Codec c (Maybe a)+maybeDecode lens i = +    I.lookup i . from . view lens <$> getCodec++-- | Decode the number with codec component identified by the lens.+-- Report error when the number is not present in the codec component. +decode :: Ord a => AtomLens c a -> Int -> Codec c a+decode lens i = maybeDecode lens i >>= \mx -> case mx of+    Just x  -> return x+    Nothing -> error $ "decode: no " ++ show i ++ " key"++-- | Run the Codec monad with the initial codec value.+-- Return both the result and the final codec state.+-- The obtained codec can be used next to perform subsequent+-- decoding or encoding.+runCodec :: c -> Codec c a -> (a, c)+runCodec codec (Codec state) = S.runState state codec++-- | Evaluate the Codec monad with the initial codec value.+-- Only the monad result will be returned.+evalCodec :: c -> Codec c a -> a+evalCodec codec (Codec state) = S.evalState state codec++-- | Execute the Codec monad with the initial codec value.+-- Only the final codec state will be returned.+execCodec :: c -> Codec c a -> c+execCodec codec (Codec state) = S.execState state codec
+ LICENSE view
@@ -0,0 +1,26 @@+Copyright (c) 2012, IPI PAN+All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions+are met:++    * Redistributions of source code must retain the above copyright+      notice, this list of conditions and the following disclaimer.++    * 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.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"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 COPYRIGHT+OWNER 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
+ monad-codec.cabal view
@@ -0,0 +1,34 @@+name:               monad-codec+version:            0.0.1+synopsis:           Monadic conversion between complex data structures and unique integers+description:+    The library provides functions for encoding and decoding complex data+    structures with unique integer numbers.  The codec structure can be+    explicitly defined which distinguishes this package from a monad-atom+    library.+license:            BSD3+license-file:       LICENSE+cabal-version:      >= 1.6+copyright:          Copyright (c) 2012 IPI PAN+author:             Jakub Waszczuk+maintainer:         waszczuk.kuba@gmail.com+stability:          experimental+category:           Control+homepage:           https://github.com/kawu/monad-codec+build-type:         Simple++library+    build-depends:+        base >= 4 && < 5+      , containers+      , lens+      , mtl >= 2++    exposed-modules:+        Control.Monad.Codec++    ghc-options: -Wall++source-repository head+    type: git+    location: git://github.com/kawu/monad-codec.git