strict-base-types (empty) → 0.1
raw patch · 6 files changed
+685/−0 lines, 6 filesdep +QuickCheckdep +aesondep +basesetup-changed
Dependencies added: QuickCheck, aeson, base, binary, deepseq, ghc-prim, lens, strict
Files
- LICENSE +26/−0
- Setup.lhs +3/−0
- src/Data/Either/Strict.hs +166/−0
- src/Data/Maybe/Strict.hs +205/−0
- src/Data/Tuple/Strict.hs +161/−0
- strict-base-types.cabal +124/−0
+ LICENSE view
@@ -0,0 +1,26 @@+Copyright (c) Roman Leshchinskiy 2006-2007++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 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 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,3 @@+#!/usr/bin/env runhaskell+> import Distribution.Simple+> main = defaultMain
+ src/Data/Either/Strict.hs view
@@ -0,0 +1,166 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE StandaloneDeriving #-}++{-# OPTIONS_GHC -fno-warn-orphans #-}++-----------------------------------------------------------------------------+-- | Copyright : (c) 2006-2007 Roman Leshchinskiy+-- (c) 2013 Simon Meier+-- License : BSD-style (see the file LICENSE)+--+-- Maintainer : Simon Meier <iridcode@gmail.com>+-- Stability : experimental+-- Portability : GHC+--+-- The strict variant of the standard Haskell 'L.Either' type and the+-- corresponding variants of the functions from "Data.Either".+--+-- Note that the strict 'Either' type is not an applicative functor, and+-- therefore also no monad. The reasons are the same as the ones for the+-- strict @Maybe@ type, which are explained in "Data.Maybe.Strict".+--+-----------------------------------------------------------------------------+module Data.Either.Strict (+ Either(Left, Right)+ , isRight+ , isLeft+ , either+ , lefts+ , rights+ , partitionEithers+) where++import Data.Strict.Either (Either (Left, Right), either, isLeft,+ isRight)+import Prelude hiding (Either (..), either)+import qualified Prelude as L++import Control.Applicative ((<$>))+import Control.DeepSeq (NFData (..))+import Control.Lens.Iso (Strict (..), iso)+import Data.Aeson (FromJSON (..), ToJSON (..))+import Data.Binary (Binary (..))+import Data.Data (Data (..), Typeable2 (..))+#if __GLASGOW_HASKELL__ >= 706+import GHC.Generics (Generic (..))+#endif+import Test.QuickCheck (Arbitrary (..))+++-- Utilities+------------+toStrict :: L.Either a b -> Either a b+toStrict (L.Left x) = Left x+toStrict (L.Right y) = Right y++toLazy :: Either a b -> L.Either a b+toLazy (Left x) = L.Left x+toLazy (Right y) = L.Right y+++-- missing instances+--------------------++deriving instance (Data a, Data b) => Data (Either a b)+deriving instance Typeable2 Either++#if __GLASGOW_HASKELL__ >= 706+deriving instance Generic (Either a b)+#endif+++-- deepseq+instance (NFData a, NFData b) => NFData (Either a b) where+ rnf = rnf . toLazy++-- binary+instance (Binary a, Binary b) => Binary (Either a b) where+ put = put . toLazy+ get = toStrict <$> get++-- aeson+instance (ToJSON a, ToJSON b) => ToJSON (Either a b) where+ toJSON = toJSON . toLazy++instance (FromJSON a, FromJSON b) => FromJSON (Either a b) where+ parseJSON val = toStrict <$> parseJSON val++-- quickcheck+instance (Arbitrary a, Arbitrary b) => Arbitrary (Either a b) where+ arbitrary = toStrict <$> arbitrary+ shrink = map toStrict . shrink . toLazy++-- lens+instance Strict (L.Either a b) (Either a b) where+ strict = iso toStrict toLazy++-- missing functions+--------------------++-- | Analogous to 'L.lefts' in "Data.Either".+lefts :: [Either a b] -> [a]+lefts x = [a | Left a <- x]++-- | Analogous to 'L.rights' in "Data.Either".+rights :: [Either a b] -> [b]+rights x = [a | Right a <- x]++-- | Analogous to 'L.partitionEithers' in "Data.Either".+partitionEithers :: [Either a b] -> ([a],[b])+partitionEithers =+ Prelude.foldr (either left right) ([],[])+ where+ left a ~(l, r) = (a:l, r)+ right a ~(l, r) = (l, a:r)+++------------------------------------------------------------------------------+-- Code required to make this module independent of the 'strict' package+------------------------------------------------------------------------------++{-+-- | The strict choice type.+--+-- Note that this type is not an applicative functor, and therefore also no+-- monad. The reasons are the same as the ones explained in the documentation+-- of the strict 'Data.Strict.Maybe.Maybe' type.+data Either a b = Left !a | Right !b+ deriving(Eq, Ord, Read, Show)+-}++{-+instance Functor (Either a) where+ fmap f = toStrict . fmap f . toLazy++instance Foldable (Either a) where+ foldr _ y (Left _) = y+ foldr f y (Right x) = f x y++ foldl _ y (Left _) = y+ foldl f y (Right x) = f y x++instance Traversable (Either e) where+ traverse _ (Left x) = pure (Left x)+ traverse f (Right x) = Right <$> f x++-- | Analogous to 'L.either' in "Data.Either".+either :: (a -> c) -> (b -> c) -> Either a b -> c+either f g = L.either f g . toLazy+-}++{-+-- | Analogous to 'L.isLeft' in "Data.Either", which will be included in base+-- \> 4.6.+isLeft :: Either a b -> Bool+isLeft (Left _) = True+isLeft (Right _) = False++-- | Analogous to 'L.isRight' in "Data.Either", which will be included in base+-- \> 4.6.+isRight :: Either a b -> Bool+isRight (Left _) = False+isRight (Right _) = True+-}
+ src/Data/Maybe/Strict.hs view
@@ -0,0 +1,205 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE StandaloneDeriving #-}++{-# OPTIONS_GHC -fno-warn-orphans #-}++-----------------------------------------------------------------------------+-- | Copyright : (c) 2006-2007 Roman Leshchinskiy+-- (c) 2013 Simon Meier+-- License : BSD-style (see the file LICENSE)+--+-- Maintainer : Simon Meier <iridcode@gmail.com>+-- Stability : experimental+-- Portability : GHC+--+-- The strict variant of the standard Haskell 'L.Maybe' type and the+-- corresponding variants of the functions from "Data.Maybe".+--+-- Note that in contrast to the standard lazy 'L.Maybe' type, the strict+-- 'Maybe' type is not an applicative functor, and therefore also not a monad.+-- The problem is the /homomorphism/ law, which states that+--+-- @'pure' f '<*>' 'pure' x = 'pure' (f x) -- must hold for all f@+--+-- This law does not hold for the expected applicative functor instance of+-- 'Maybe', as this instance does not satisfy @pure f \<*\> pure _|_ = pure (f+-- _|_)@ for @f = const@.+--+-----------------------------------------------------------------------------++module Data.Maybe.Strict (+ Maybe(Nothing,Just)+ , maybe++ , isJust+ , isNothing+ , fromJust+ , fromMaybe+ , listToMaybe+ , maybeToList+ , catMaybes+ , mapMaybe+) where++import Prelude hiding (Maybe (..), maybe)+import qualified Prelude as L++import Control.Applicative ((<$>))+import Control.DeepSeq (NFData (..))+import Control.Lens.Iso (Strict (..), iso)+import Data.Aeson (FromJSON (..), ToJSON (..))+import Data.Binary (Binary (..))+import Data.Data (Data (..), Typeable1 (..))+import Data.Monoid (Monoid (..))+import Data.Strict.Maybe (Maybe (Nothing, Just), fromJust,+ fromMaybe, isJust, isNothing, maybe)+#if __GLASGOW_HASKELL__ >= 706+import GHC.Generics (Generic (..))+#endif+import Test.QuickCheck (Arbitrary (..))+++-- utilities+------------++toStrict :: L.Maybe a -> Maybe a+toStrict L.Nothing = Nothing+toStrict (L.Just x) = Just x++toLazy :: Maybe a -> L.Maybe a+toLazy Nothing = L.Nothing+toLazy (Just x) = L.Just x++deriving instance Data a => Data (Maybe a)+deriving instance Typeable1 Maybe++#if __GLASGOW_HASKELL__ >= 706+deriving instance Generic (Maybe a)+#endif++instance Monoid a => Monoid (Maybe a) where+ mempty = Nothing++ Nothing `mappend` _ = Nothing+ _ `mappend` Nothing = Nothing+ Just x1 `mappend` Just x2 = Just (x1 `mappend` x2)++-- deepseq+instance NFData a => NFData (Maybe a) where+ rnf = rnf . toLazy++-- binary+instance Binary a => Binary (Maybe a) where+ put = put . toLazy+ get = toStrict <$> get++-- aeson+instance ToJSON a => ToJSON (Maybe a) where+ toJSON = toJSON . toLazy++instance FromJSON a => FromJSON (Maybe a) where+ parseJSON val = toStrict <$> parseJSON val++-- quickcheck+instance Arbitrary a => Arbitrary (Maybe a) where+ arbitrary = toStrict <$> arbitrary+ shrink = map toStrict . shrink . toLazy++-- lens+instance Strict (L.Maybe a) (Maybe a) where+ strict = iso toStrict toLazy+++-- | Analogous to 'L.listToMaybe' in "Data.Maybe".+listToMaybe :: [a] -> Maybe a+listToMaybe [] = Nothing+listToMaybe (a:_) = Just a++-- | Analogous to 'L.maybeToList' in "Data.Maybe".+maybeToList :: Maybe a -> [a]+maybeToList Nothing = []+maybeToList (Just x) = [x]++-- | Analogous to 'L.catMaybes' in "Data.Maybe".+catMaybes :: [Maybe a] -> [a]+catMaybes ls = [x | Just x <- ls]++-- | Analogous to 'L.mapMaybe' in "Data.Maybe".+mapMaybe :: (a -> Maybe b) -> [a] -> [b]+mapMaybe _ [] = []+mapMaybe f (x:xs) = case f x of+ Nothing -> rs+ Just r -> r:rs+ where+ rs = mapMaybe f xs++------------------------------------------------------------------------------+-- Code required to make this module independent of the 'strict' package+------------------------------------------------------------------------------++{-+-- | The type of strict optional values.+--+-- In contrast to the standard lazy 'L.Maybe' type, this type is not an+-- applicative functor, and therefore also not a monad. The problem is the+-- /homomorphism/ law, which states that+--+-- @'pure' f '<*>' 'pure' x = 'pure' (f x)@+--+-- must hold for all @f@. This law does not hold for the expected applicative+-- functor instance of 'Maybe', as this instance does not satisfy @pure f+-- \<*\> pure _|_ = pure (f _|_)@ for @f = const@.+data Maybe a = Nothing | Just !a+ deriving(Eq, Ord, Show, Read, Data, Typeable, Generic)+-}++-- instances+------------++{-+instance StrictType (Maybe a) where+ type LazyVariant (Maybe a) = L.Maybe a++ toStrict L.Nothing = Nothing+ toStrict (L.Just x) = Just x++ toLazy Nothing = L.Nothing+ toLazy (Just x) = L.Just x++instance Functor Maybe where+ fmap f = toStrict . fmap f . toLazy++instance Foldable Maybe where+ foldr f y = Foldable.foldr f y . toLazy+ foldl f y = Foldable.foldl f y . toLazy++instance Traversable Maybe where+ traverse _ Nothing = pure Nothing+ traverse f (Just x) = Just <$> f x+-}++{-+-- | Analogous to 'L.isJust' in "Data.Maybe".+isJust :: Maybe a -> Bool+isJust = L.isJust . toLazy++-- | Analogous to 'L.isNothing' in "Data.Maybe".+isNothing :: Maybe a -> Bool+isNothing = L.isNothing . toLazy++-- | Analogous to 'L.fromJust' in "Data.Maybe".+fromJust :: Maybe a -> a+fromJust Nothing = error "Data.Strict.Maybe.fromJust: Nothing"+fromJust (Just x) = x++-- | Analogous to 'L.fromMaybe' in "Data.Maybe".+fromMaybe :: a -> Maybe a -> a+fromMaybe x = L.fromMaybe x . toLazy++-- | Analogous to 'L.maybe' in "Data.Maybe".+maybe :: b -> (a -> b) -> Maybe a -> b+maybe x f = L.maybe x f . toLazy+-}
+ src/Data/Tuple/Strict.hs view
@@ -0,0 +1,161 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE StandaloneDeriving #-}++{-# OPTIONS_GHC -fno-warn-orphans #-}+-----------------------------------------------------------------------------+-- | Copyright : (c) 2006-2007 Roman Leshchinskiy+-- (c) 2013 Simon Meier+-- License : BSD-style (see the file LICENSE)+--+-- Maintainer : Simon Meier <iridcode@gmail.com>+-- Stability : experimental+-- Portability : GHC+--+-- The strict variant of the standard Haskell pairs and the corresponding+-- variants of the functions from "Data.Tuple".+--+-----------------------------------------------------------------------------+++module Data.Tuple.Strict (+ Pair(..)+ , fst+ , snd+ , curry+ , uncurry+ , zip+ , unzip+) where++import Data.Strict.Tuple (Pair ((:!:)), curry, fst, snd, uncurry)+import Prelude hiding (curry, fst, snd, uncurry, unzip,+ zip)+import qualified Prelude as L++import Control.Applicative ((<$>))+import Control.DeepSeq (NFData (..))+import Control.Lens.Iso (Strict (..), iso)+import Data.Aeson (FromJSON (..), ToJSON (..))+import Data.Binary (Binary (..))+import Data.Data (Data (..), Typeable2 (..))+import Data.Monoid (Monoid (..))+#if __GLASGOW_HASKELL__ >= 706+import GHC.Generics (Generic (..))+#endif+import Test.QuickCheck (Arbitrary (..))++-- Utilities+------------++toStrict :: (a, b) -> Pair a b+toStrict (a, b) = a :!: b++toLazy :: Pair a b -> (a, b)+toLazy (a :!: b) = (a, b)+++-- missing instances+--------------------++deriving instance (Data a, Data b) => Data (Pair a b)+deriving instance Typeable2 Pair++-- fails with compiler panic on GHC 7.4.2+#if __GLASGOW_HASKELL__ >= 706+deriving instance Generic (Pair a b)+#endif++instance (Monoid a, Monoid b) => Monoid (Pair a b) where+ mempty = mempty :!: mempty+ (x1 :!: y1) `mappend` (x2 :!: y2) = (x1 `mappend` x2) :!: (y1 `mappend` y2)++-- deepseq+instance (NFData a, NFData b) => NFData (Pair a b) where+ rnf = rnf . toLazy++-- binary+instance (Binary a, Binary b) => Binary (Pair a b) where+ put = put . toLazy+ get = toStrict <$> get++-- aeson+instance (ToJSON a, ToJSON b) => ToJSON (Pair a b) where+ toJSON = toJSON . toLazy++instance (FromJSON a, FromJSON b) => FromJSON (Pair a b) where+ parseJSON val = toStrict <$> parseJSON val++-- quickcheck+instance (Arbitrary a, Arbitrary b) => Arbitrary (Pair a b) where+ arbitrary = toStrict <$> arbitrary+ shrink = map toStrict . shrink . toLazy++-- lens+instance Strict (a, b) (Pair a b) where+ strict = iso toStrict toLazy++++{- To be added once they make it to base++instance Foldable (Pair e) where+ foldMap f (_,x) = f x++instance Traversable (Pair e) where+ traverse f (e,x) = (,) e <$> f x+-}+++-- missing functions+--------------------++-- | Zip for strict pairs (defined with zipWith).+zip :: [a] -> [b] -> [Pair a b]+zip x y = zipWith (:!:) x y++-- | Unzip for stict pairs into a (lazy) pair of lists.+unzip :: [Pair a b] -> ([a], [b])+unzip x = ( map fst x+ , map snd x+ )++------------------------------------------------------------------------------+-- Code required to make this module independent of the 'strict' package+------------------------------------------------------------------------------++{-+-- | The type of strict pairs. Note that+--+-- > (x :!: _|_) = (_|_ :!: y) = _|_+data Pair a b = !a :!: !b+ deriving(Eq, Ord, Show, Read, Bounded, Ix, Data, Typeable, Generic)++instance StrictType (Pair a b) where+ type LazyVariant (Pair a b) = (a, b)++ toStrict (a, b) = a :!: b+ toLazy (a :!: b) = (a, b)++instance Functor (Pair e) where+ fmap f = toStrict . fmap f . toLazy++-- | Extract the first component of a strict pair.+fst :: Pair a b -> a+fst (x :!: _) = x++-- | Extract the second component of a strict pair.+snd :: Pair a b -> b+snd (_ :!: y) = y++-- | Curry a function on strict pairs.+curry :: (Pair a b -> c) -> a -> b -> c+curry f x y = f (x :!: y)++-- | Convert a curried function to a function on strict pairs.+uncurry :: (a -> b -> c) -> Pair a b -> c+uncurry f (x :!: y) = f x y+-}+
+ strict-base-types.cabal view
@@ -0,0 +1,124 @@+Name: strict-base-types+Version: 0.1+Synopsis: Strict variants of the types provided in base.+Category: Data+Description:+ It is common knowledge that lazy datastructures can lead to space-leaks.+ This problem is particularly prominent, when using lazy datastructures to+ store the state of a long-running application in memory. The easiest+ solution to this problem is to use fully strict types to store such state+ values. By \"fully strict types\" we mean types for whose values it holds+ that, if they are in weak-head normal form, then they are also in normal+ form. Intuitively, this means that values of fully strict types cannot+ contain unevaluated thunks.+ .+ To define a fully strict datatype, one typically uses the following recipe.+ .+ 1. Make all fields of every constructor strict; i.e., add a bang to+ all fields.+ .+ 2. Use only strict types for the fields of the constructors. + .+ The second requirement is problematic as it rules out the use of+ the standard Haskell 'Maybe', 'Either', and pair types. This library+ solves this problem by providing strict variants of these types and their+ corresponding standard support functions and type-class instances. + .+ Note that this library does currently not provide fully strict lists.+ They can be added if they are really required. However, in many cases one+ probably wants to use unboxed or strict boxed vectors from the 'vector'+ library (<http://hackage.haskell.org/package/vector>) instead of strict+ lists. Moreover, instead of @String@s one probably wants to use strict+ @Text@ values from the @text@ library+ (<http://hackage.haskell.org/package/text>).+ .+ This library comes with batteries included; i.e., missing instances+ for type-classes from the @deepseq@, @binary@, @aeson@, @QuickCheck@, and+ @lens@ packages are included. Of particluar interest is the @Strict@+ type-class provided by the lens library+ (<http://hackage.haskell.org/packages/archive/lens/3.9.0.2/doc/html/Control-Lens-Iso.html#t:Strict>).+ It is used in the following example to simplify the modification of+ strict fields.+ .+ > (-# LANGUAGE TemplateHaskell #-) -- replace with curly braces, + > (-# LANGUAGE OverloadedStrings #-) -- the Haddock prologues are a P.I.T.A!+ > + > import Control.Lens ( (.=), Strict(strict), from, Iso', makeLenses)+ > import Control.Monad.State.Strict (State)+ > import qualified Data.Map as M+ > import qualified Data.Maybe.Strict as S+ > import qualified Data.Text as T+ > + > -- | An example of a state record as it could be used in a (very minimal)+ > -- role-playing game.+ > data GameState = GameState+ > ( _gsCooldown :: !(S.Maybe Int)+ > , _gsHealth :: !Int+ > ) -- replace with curly braces, *grmbl*+ > + > makeLenses ''GameState+ > + > -- The isomorphism, which converts a strict field to its lazy variant+ > lazy :: Strict lazy strict => Iso' strict lazy+ > lazy = from strict+ > + > type Game = State GameState+ > + > cast :: T.Text -> Game ()+ > cast spell =+ > gsCooldown.lazy .= M.lookup spell spellDuration+ > -- ... implement remainder of spell-casting ...+ > where+ > spellDuration = M.fromList [("fireball", 5)]+ .+ See+ <http://www.haskellforall.com/2013/05/program-imperatively-using-haskell.html>+ for a gentle introduction to lenses and state manipulation.+ .+ Note that this package uses the types provided by the 'strict' package+ (<http://hackage.haskell.org/package/strict>), but organizes them a bit+ differently. More precisely, the @strict-base-types@ package+ .+ - only provides the fully strict variants of types from 'base',+ .+ - is in-sync with the current base library (base-4.6), + .+ - provides the missing instances for (future) Haskell platform packages, and+ .+ - conforms to the standard policy that strictness variants of an existing+ datatype are identified by suffixing \'Strict\' or \'Lazy\' in the+ module hierarchy.+++License: BSD3+License-File: LICENSE+Author: Roman Leshchinskiy <rl@cse.unsw.edu.au>,+ Simon Meier <iridcode@gmail.com>+Maintainer: Simon Meier <iridcode@gmail.com>+Copyright: (c) 2006-2008 by Roman Leshchinskiy+ (c) 2013 by Simon Meier+Homepage: https://github.com/meiersi/strict-base-types+Cabal-Version: >= 1.6+Build-type: Simple++source-repository head+ type: git+ location: https://github.com/meiersi/strict-base-types.git++library+ build-depends: + base >= 4.5 && < 5+ , lens >= 3.9+ , QuickCheck >= 2+ , aeson >= 0.6+ , binary >= 0.5+ , deepseq >= 1.3+ , strict == 0.3.*+ , ghc-prim+ hs-source-dirs: src+ exposed-modules:+ Data.Tuple.Strict+ Data.Maybe.Strict+ Data.Either.Strict+ ghc-options: -Wall+