Drastic Prelude changes imminent
Edward Kmett
ekmett at gmail.com
Sun Feb 1 21:26:15 UTC 2015
I didn't say arbitrary.
At the risk of an overly complicated example, just because I have it handy:
In the following type: rep 1000 "a" folds in logarithmic time, lots of
operations actually get to exploit the obliviousness of (*>) and (<*) and
(>>) to one argument or the other's values to exploit replication heavily
for parts of the result as well. This is needed to match the asymptotics of
Fritz Henglein's linear time table joins in a final encoding for instance.
data Table a = Table
{ count :: {-# UNPACK #-} !Int
, runTable :: forall r. Monoid r => (a -> r) -> r
}
instance IsList (Table a) where
type Item (Table a) = a
fromList = foldMap pure
toList = Foldable.toList
fromListN n xs = Table n (`foldMap` xs)
instance Functor Table where
fmap f (Table i m) = Table i $ \k -> m (k.f)
instance Foldable Table where
foldMap f (Table _ m) = m f
foldr f z (Table _ m) = m (Endo . f) `appEndo` z
instance Monoid (Table a) where
mempty = Table 0 $ \_ -> mempty
mappend (Table i m) (Table j n) = Table (i + j) $ \k -> m k `mappend` n k
newtype Ap f a = Ap { runAp :: f a }
instance (Applicative f, Monoid a) => Monoid (Ap f a) where
mempty = Ap (pure mempty)
mappend (Ap m) (Ap n) = Ap (liftA2 mappend m n)
instance Traversable Table where
-- this reassembles the result with sharing!
traverse f = runAp . foldMap (Ap . fmap pure . f)
instance Applicative Table where
pure a = Table 1 $ \k -> k a
Table n as <*> Table m bs = Table (n * m) $ \k -> as $ \f -> bs (k . f)
Table n as <* Table m _ = Table (n * m) $ \k -> as (rep m . k)
Table n _ *> Table m bs = Table (n * m) $ rep n . bs
-- peasant multiplication
rep :: Monoid m => Int -> m -> m
rep y0 x0
| y0 <= 0 = mempty
| otherwise = f x0 y0
where
f x y
| even y = f (mappend x x) (quot y 2)
| y == 1 = x
| otherwise = g (mappend x x) (quot (y - 1) 2) x
g x y z
| even y = g (mappend x x) (quot y 2) z
| y == 1 = mappend x z
| otherwise = g (mappend x x) (quot (y - 1) 2) (mappend x z)
bag :: (forall m. Monoid m => (a -> m) -> m) -> Table a
bag k = Table (getSum $ k $ \_ -> Sum 1) k
instance Monad Table where
return a = Table 1 $ \k -> k a
as >>= f = bag $ \k -> runTable as $ \a -> runTable (f a) k
(>>) = (*>)
fail _ = empty
instance MonadZip Table where
-- we can handle this in a smarter fashion now
mzipWith k m n = foldMap pure $ mzipWith k (Foldable.toList m)
(Foldable.toList n)
munzip m = (fmap fst m, fmap snd m)
instance Alternative Table where
empty = Table 0 $ \_ -> mempty
Table m as <|> Table n bs = Table (m + n) $ \k -> as k `mappend` bs k
instance MonadPlus Table where
mzero = Table 0 $ \_ -> mempty
Table m as `mplus` Table n bs = Table (m + n) $ \k -> as k `mappend` bs k
instance MonadFix Table where
mfix a2ba = foldMap pure $ mfix (Foldable.toList . a2ba)
etc.
On Sun, Feb 1, 2015 at 4:17 PM, Roman Cheplyaka <roma at ro-che.info> wrote:
> On 01/02/15 22:56, Edward Kmett wrote:
> > sum = getSum . foldMap sum
> >
> > is the implementation that ensures that it doesn't destroy the
> > asymptotics of the number of uses of 'mappend' in foldMap.
> >
> > The right container can readily fold 2^20th a's with 20 mappends.
>
> Fold 2^20 *arbitrary* a's? What kind of container is that?
>
> Roman
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.haskell.org/pipermail/libraries/attachments/20150201/630b29a4/attachment-0001.html>
More information about the Libraries
mailing list