vault (empty) → 0.1.0.0
raw patch · 6 files changed
+233/−0 lines, 6 filesdep +basedep +containerssetup-changed
Dependencies added: base, containers
Files
- LICENSE +30/−0
- Readme.md +44/−0
- Setup.hs +2/−0
- src/Data/Vault.hs +57/−0
- src/Data/Vault/ST.hs +66/−0
- vault.cabal +34/−0
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright (c)2011, Heinrich Apfelmus++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.++ * Neither the name of Heinrich Apfelmus nor the names of other+ contributors may be used to endorse or promote products derived+ from this software without specific prior written permission.++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.
+ Readme.md view
@@ -0,0 +1,44 @@+*Vault* is a tiny library that provides a single data structure called *vault*.++A *vault* is a type-safe, persistent storage for values of arbitrary types. Like `IORef`, I want to be able to store values of any type in it, but unlike `IORef`, I want the storage space to behave like a persistent, first-class data structure, as appropriate for a purely functional language.++It is analogous to a bank vault, where you can access different bank boxes with different keys; hence the name.++In other words, a vault is an abstract data type with the following basic signature++ data Key a+ data Vault++ newKey :: IO (Key a)+ empty :: Vault+ lookup :: Key a -> Vault -> Maybe a+ insert :: Key a -> a -> Vault -> Vault+ delete :: Key a -> Vault -> Vault++A few common functions for finite maps, like `adjust` and `union`, are provided as well.+++This library was created thanks to the feedback on my blog post [Vault - a persistent store for values of arbitrary types][1].++ [1]: http://apfelmus.nfshost.com/blog/2011/09/04-vault.html+++Installation+============+The whole thing is [available on hackage][hackage], so you just have to type++ cabal update+ cabal install vault++ [hackage]: http://hackage.haskell.org/package/vault++Feedback+========+Use the [issue tracker][2] or send an [email to the maintainer][3].++ [2]: https://github.com/HeinrichApfelmus/vault/issues+ [3]: mailto:apfelmus@quantentunnel.de++++
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ src/Data/Vault.hs view
@@ -0,0 +1,57 @@+{-----------------------------------------------------------------------------+ Vault+ + A typed, persistent store for values of arbitrary types+ + This implementation uses unsafeCoerce for reasons of efficiency.+ See http://apfelmus.nfshost.com/blog/2011/09/04-vault.html+ for an implementation that doesn't need to bypass the type checker.+------------------------------------------------------------------------------}+module Data.Vault (+ Vault, Key,+ empty, newKey, lookup, insert, adjust, delete, union,+ ) where++import Prelude hiding (lookup)+import Control.Monad.ST+import qualified Data.Vault.ST as ST++-- | A typed, persistent store for values of arbitrary types.+-- +-- This variant is the simplest and creates keys in the 'IO' monad.+-- See the module "Data.Vault.ST" if you want to use it with the 'ST' monad instead.+--+-- > instance Monoid Vault+type Vault = ST.Vault RealWorld+-- | Keys for the vault.+--+-- > Key :: * -> *+type Key = ST.Key RealWorld++-- | The empty vault.+empty :: Vault+empty = ST.empty++-- | Create a new key for use with a vault.+newKey :: IO (Key a)+newKey = stToIO ST.newKey++-- | Lookup the value of a key in the vault.+lookup :: Key a -> Vault -> Maybe a+lookup = ST.lookup++-- | Insert a value for a given key. Overwrites any previous value.+insert :: Key a -> a -> Vault -> Vault+insert = ST.insert++-- | Adjust the value for a given key if it's present in the vault.+adjust :: (a -> a) -> Key a -> Vault -> Vault+adjust = ST.adjust++-- | Delete a key from the vault.+delete :: Key a -> Vault -> Vault+delete = ST.delete++-- | Merge two vaults (left-biased).+union :: Vault -> Vault -> Vault+union = ST.union
+ src/Data/Vault/ST.hs view
@@ -0,0 +1,66 @@+{-----------------------------------------------------------------------------+ Vault+ + A typed, persistent store for values of arbitrary types+ + This implementation uses unsafeCoerce for reasons of efficiency.+ See http://apfelmus.nfshost.com/blog/2011/09/04-vault.html+ for an implementation that doesn't need to bypass the type checker.+------------------------------------------------------------------------------}+module Data.Vault.ST (+ Vault, Key,+ empty, newKey, lookup, insert, adjust, delete, union,+ ) where++import Prelude hiding (lookup)+import Data.Monoid hiding (Any)+import Data.Functor+import Data.Map (Map)+import qualified Data.Map as Map+import Data.Unique+import Control.Monad.ST++import GHC.Exts (Any) -- ghc specific tricks+import Unsafe.Coerce (unsafeCoerce)++-- | A typed, persistent store for values of arbitrary types.+-- +-- This variant has more complex types so that you can create keys in the 'ST' monad.+-- See the module "Data.Vault" if you'd like to use a simpler version with the 'IO' monad.+-- You can also use both variants simultaneously; they share a single representation.+newtype Vault s = Vault (Map Unique Any)+-- | Keys for the vault.+newtype Key s a = Key Unique++instance Monoid (Vault s) where+ mempty = empty+ mappend = union++-- | The empty vault.+empty :: Vault s+empty = Vault Map.empty++-- | Create a new key for use with a vault.+newKey :: ST s (Key s a)+newKey = Key <$> unsafeIOToST newUnique++-- | Lookup the value of a key in the vault.+lookup :: Key s a -> Vault s -> Maybe a+lookup (Key k) (Vault m) = unsafeCoerce <$> Map.lookup k m ++-- | Insert a value for a given key. Overwrites any previous value.+insert :: Key s a -> a -> Vault s -> Vault s+insert (Key k) x (Vault m) = Vault $ Map.insert k (unsafeCoerce x) m++-- | Adjust the value for a given key if it's present in the vault.+adjust :: (a -> a) -> Key s a -> Vault s -> Vault s+adjust f (Key k) (Vault m) = Vault $ Map.alter f' k m+ where f' = unsafeCoerce . f . unsafeCoerce++-- | Delete a key from the vault.+delete :: Key s a -> Vault s -> Vault s+delete (Key k) (Vault m) = Vault $ Map.delete k m++-- | Merge two vaults (left-biased).+union :: Vault s -> Vault s -> Vault s+union (Vault m) (Vault m') = Vault $ Map.union m m'
+ vault.cabal view
@@ -0,0 +1,34 @@+Name: vault+Version: 0.1.0.0+Synopsis: a typed, persistent store for values of arbitrary types+Description:+ A /vault/ is a typed, persistent store for values of arbitrary types.+ It's like having first-class access to the storage space behind IORefs.+ .+ The data structure is analogous to a bank vault,+ where you can access different bank boxes with different keys;+ hence the name.+ +Category: Data+License: BSD3+License-file: LICENSE+Author: Heinrich Apfelmus, Elliott Hird+Maintainer: Heinrich Apfelmus <apfelmus at quantentunnel de>+Homepage: https://github.com/HeinrichApfelmus/vault+Copyright: (c) Heinrich Apfelmus 2011++build-type: Simple+cabal-version: >= 1.6++extra-source-files: Readme.md++source-repository head+ type: git+ location: git://github.com/HeinrichApfelmus/vault.git++Library+ hs-source-dirs: src+ build-depends: base == 4.*, containers == 0.4.*+ ghc-options: -Wall+ exposed-modules: Data.Vault, Data.Vault.ST+