generic finger-tree structure (http://staff.city.ac.uk/~ross/papers/FingerTree.html)
#20IntervalMap almost admits an applicative instance
IntervalMap very nearly has an applicative instance:
getIntersection :: Ord a => Interval a -> Interval a -> Maybe (Interval a)
getIntersection (Interval a1 a2) (Interval b1 b2) = do
let lo = max a1 b1
hi = min a2 b2
case lo < hi of
True -> Just $ Interval lo hi
False -> Nothing
instance Applicative IntervalMap where
pure = IM.singleton everywhere
liftA2 f ma mb = mconcat $ do
(ai, a) <- IM.toList ma
(bi, b) <- IM.intersections ai mb
i <- maybeToList $ getIntersection ai bi
pure $ IM.singleton i $ f a b
where everywhere :: Interval k. Of course, everywhere is currently impossible to implement forall k, but the near existence of this instance makes me think the articulation of IntervalMap is not quite right.
There are a few solutions here. We could stick everywhere in a typeclass and require it for the Applicative instance. This has the advantage of being backwards compatible, but it's not beautiful.
Better, I think, would be to change Interval:
data Interval v
= Everywhere
| OpenStart v
| OpenEnd v
| Interval v v We could also define
everywhereaseverywhere :: (Bounded v) => Interval v everywhere = Interval minBound maxBoundThat seems less general, but if we define
data WithBounds a = Bottom | Middle a | Top deriving (Eq, Ord, Read, Show) instance Bounded (WithBounds a) where minBound = Bottom maxBound = Topthen your
Interval visInterval (WithBounds v), so the existing definition subsumes it.I also suspect there may be more efficient approaches than using
toList, but I haven't looked too closely.Right, sorry, yeah! I thought about using
Bounded, butBoundedrequiresEnumand most of the types I want to use this for are notEnum:)I just looked and apparently Enum is not a superclass of Bounded? Have I been taking crazy pills all these years??? In that case, yes, I agree that taking on the bounded constraint is a good solution, and that we can use
WithBoundsto get it for free.- status set to closed
Enumis a superclass ofIntegral, but hasn't been a superclass ofBounded, at least since Haskell 98.- status set to open
Reopening this because there is still the first part. It might be useful to have an efficient implementation of
intersectionWith :: (Ord v) => (a -> b -> c) -> IntervalMap v a -> IntervalMap v b -> IntervalMap v cif that were possible. It would then be easy to define an
Applicativeinstance with aBoundedconstraint.It's even a monad:
instance (Bounded v, Ord v) => Monad (IntervalMap v) where ma >>= k = fromList [(Interval (max lo_a lo_b) (min hi_a hi_b), b) | (ia@(Interval lo_a hi_a), a) <- assocs ma, (Interval lo_b hi_b, b) <- intersections ia (k a)]