unfoldable 0.1.0 → 0.2.0
raw patch · 3 files changed
+15/−8 lines, 3 files
Files
- src/Data/Splittable.hs +9/−7
- src/Data/Unfoldable.hs +5/−0
- unfoldable.cabal +1/−1
src/Data/Splittable.hs view
@@ -33,17 +33,20 @@ n `mod'` m = n `mod` m data Left = L+-- | Always choose the first item. instance Splittable Left where split = replicate choose fs = head fs getInt L = 0 data Right = R+-- | Always choose the last item. instance Splittable Right where split = replicate choose fs = last fs getInt R = 0 +-- | Choose randomly instance Splittable R.StdGen where split 0 _ = [] split 1 s = [s]@@ -51,6 +54,8 @@ choose fs s = let (n, s') = R.next s in fs !! (n `mod` length fs) $ s' getInt = fst . R.next +-- | The 'Integer' instance uses modulo to choose, and splits breadth-first by +-- distributing bits in a round-robin fashion. instance Splittable Integer where split n t = split' 1 (t, replicate n 0) where@@ -59,23 +64,20 @@ choose fs s = let (s', n) = s `divMod` toInteger (length fs) in fs !! fromInteger n $ s' getInt = fromInteger +-- | The @(a, b)@ instance uses only @a@ for 'choose' and @b@ for 'getInt'. 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+ getInt (_, b) = getInt b +-- | Choose between 2 ways to split and choose. 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 +-- | Reverse the split output and the choose input. instance Splittable s => Splittable (Dual s) where split n = map Dual . reverse . split n . getDual choose fs = choose (map (. Dual) $ reverse fs) . getDual
src/Data/Unfoldable.hs view
@@ -53,18 +53,23 @@ -- and an initial seed, generate a structure. unfoldMap :: Splittable s => (s -> a) -> s -> f a +-- | The same as @unfoldMap id@. unfold :: (Unfoldable f, Splittable s) => s -> f s unfold = unfoldMap id +-- | Always choose the first constructor. leftMost :: Unfoldable f => f () leftMost = unfoldMap (const ()) L +-- | Always choose the last constructor. rightMost :: Unfoldable f => f () rightMost = unfoldMap (const ()) R +-- | Count the number of times 'to' is used, and split the seed in that many parts. spread :: Splittable s => State ([s], Int) a -> s -> a spread f s = let (a, (_, i)) = runState f (split i s, 0) in a +-- | Signal to 'spread' that this is a subpart that needs a seed. to :: (s -> a) -> State ([s], Int) a to f = state $ \(ss, i) -> (f (head ss), (tail ss, i + 1))
unfoldable.cabal view
@@ -1,5 +1,5 @@ Name: unfoldable-Version: 0.1.0+Version: 0.2.0 Synopsis: Class of data structures that can be unfolded from a seed value. Homepage: https://github.com/sjoerdvisscher/unfoldable License: BSD3