packages feed

unfoldable (empty) → 0.0.0

raw patch · 5 files changed

+211/−0 lines, 5 filesdep +basedep +randomdep +transformerssetup-changed

Dependencies added: base, random, transformers

Files

+ LICENSE view
@@ -0,0 +1,30 @@+Copyright (c)2012, Sjoerd Visscher++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 Sjoerd Visscher 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.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ src/Data/Splittable.hs view
@@ -0,0 +1,74 @@+{-# LANGUAGE ScopedTypeVariables #-}+module Data.Splittable (+    Splittable(..)+  +  , boundedEnum+  +  , Left(..)+  , Right(..)+  +  ) where ++import qualified System.Random as R+import Data.List (mapAccumR)++-- | Splittable datatypes are datatypes that can be used as seeds for unfolds.+class Splittable s where+  -- | @split n s@ splits the seed @s@ in @n@ seeds. +  split  :: Int -> s -> [s]+  -- | @choose fs s@ uses part of the seed @s@ to choose a function from the list @fs@,+  -- and passes the remainder to that function.+  choose :: [s -> x] -> s -> x+  -- | Convert the seed value to an @int@.+  getInt :: s -> Int++-- | If a datatype is bounded and enumerable, we can use 'getInt' to produce a value from a seed.+boundedEnum :: forall s a. (Splittable s, Bounded a, Enum a) => s -> a+boundedEnum s = toEnum $ (getInt s `mod` (1 + ub - lb)) + lb+  where +    lb = fromEnum (minBound :: a)+    ub = fromEnum (maxBound :: a)++data Left = L+instance Splittable Left where+  split = replicate+  choose fs = head fs+  getInt L = 0++data Right = R+instance Splittable Right where+  split = replicate+  choose fs = last fs+  getInt R = maxBound++instance Splittable R.StdGen where+  split 0 _ = []+  split 1 s = [s]+  split n s = let (s1, s2) = R.split s in s1 : split (n - 1) s2 +  choose fs s = let (n, s') = R.next s in fs !! (n `mod` length fs) $ s'+  getInt = fst . R.next++instance Splittable Integer where+  split n t = split' 1 (t, replicate n 0)+    where+      split' _ (0, l) = l+      split' p (s, l) = split' (p * 2) $ mapAccumR (\s' i -> let (s'', b) = s' `divMod` 2 in (s'', i + b * p)) s l+  choose fs s = let (s', n) = s `divMod` toInteger (length fs) in fs !! fromInteger n $ s'+  getInt = fromInteger++instance (Splittable a, Splittable b) => Splittable (a, b) where+  split n (a, b) = zip (split n a) (split n b)+  choose = uncurry . choose . map curry+  getInt (a, b) = go (getInt a) (getInt b)+    where+      go 0 0 = 0+      go m n = go m' n' * 4 + mb * 2 + nb+        where+          (m', mb) = m `divMod` 2+          (n', nb) = n `divMod` 2++instance (Splittable a, Splittable b) => Splittable (Either a b) where+  split n   = either (map Left . split n) (map Right . split n)+  choose fs = either (choose (map (. Left) fs)) (choose (map (. Right) fs))+  getInt (Left a) = getInt a * 2+  getInt (Right a) = getInt a * 2 + 1
+ src/Data/Unfoldable.hs view
@@ -0,0 +1,78 @@+module Data.Unfoldable (++    Unfoldable(..)++  -- ** Specific unfolds+  , unfold+  , leftMost+  , rightMost++  -- ** Helper functions+  , spread+  , to++  ) where+    +import Control.Applicative+import Control.Monad.Trans.State+import Data.Splittable++-- | Data structures that can be unfolded.+--+-- For example, given a data type+--+-- > data Tree a = Empty | Leaf a | Node (Tree a) a (Tree a)+--+-- a suitable instance would be+--+-- > instance Unfoldable Tree where+-- >   unfoldMap f = choose+-- >     [ spread $ pure Empty+-- >     , spread $ Leaf <$> to f+-- >     , spread $ Node <$> to (unfoldMap f) <*> to f <*> to (unfoldMap f)+-- >     ]+--+-- i.e. it follows closely the instance for 'Traversable', with the addition of 'choose', 'spread' and 'to'.+-- +-- The instance can be simplified to:+--+-- > instance Unfoldable Tree where+-- >   unfoldMap f = choose+-- >     [ const Empty+-- >     , Leaf . f+-- >     , spread $ Node <$> to (unfoldMap f) <*> to f <*> to (unfoldMap f)+-- >     ]+class Unfoldable f where+  -- | Given a function to generate an element from a seed, +  -- and an initial seed, generate a structure.+  unfoldMap :: Splittable s => (s -> a) -> s -> f a++unfold :: (Unfoldable f, Splittable s) => s -> f s+unfold = unfoldMap id++leftMost :: Unfoldable f => f ()+leftMost = unfoldMap (const ()) L++rightMost :: Unfoldable f => f ()+rightMost = unfoldMap (const ()) R++spread :: Splittable s => State ([s], Int) a -> s -> a+spread f s = let (a, (_, i)) = runState f (split i s, 0) in a++to :: (s -> a) -> State ([s], Int) a+to f = state $ \(ss, i) -> (f (head ss), (tail ss, i + 1))++instance Unfoldable [] where+  unfoldMap f = go+    where+      go = choose [const [], spread $ (:) <$> to f <*> to go]++instance Unfoldable Maybe where+  unfoldMap f = choose [const Nothing, Just . f]++instance (Bounded a, Enum a) => Unfoldable (Either a) where+  unfoldMap f = choose [Left . boundedEnum, Right . f]++instance (Bounded a, Enum a) => Unfoldable ((,) a) where+  unfoldMap f = spread $ (,) <$> to boundedEnum <*> to f+
+ unfoldable.cabal view
@@ -0,0 +1,27 @@+Name:                unfoldable+Version:             0.0.0+Synopsis:            Class of data structures that can be unfolded from a seed value.+Homepage:            https://github.com/sjoerdvisscher/unfoldable+License:             BSD3+License-file:        LICENSE+Author:              Sjoerd Visscher+Maintainer:          sjoerd@w3future.com+Category:            Generics+Build-type:          Simple+Cabal-version:       >= 1.6++Library+  HS-Source-Dirs:  src+  +  Exposed-modules:+    Data.Splittable+    Data.Unfoldable  +  +  Build-depends:+      base         >= 4   && < 5 +    , transformers >= 0.2 && < 0.4+    , random       >= 1.0 && < 1.1++source-repository head+  type:     git+  location: git://github.com/sjoerdvisscher/unfoldable.git