I've successfully defined Category, Functor, Semigroup, Monoid constrained. Now I'm stuck with Data.Foldable.Constrained. More precisely, I seem to have correctly defined the unconstrained functions fldl and fldMp, but I can't get them to be accepted as Foldable.Constrained instances. My definition attempt is inserted as a comment.
{-# LANGUAGE OverloadedLists, GADTs, TypeFamilies, ConstraintKinds,
FlexibleInstances, MultiParamTypeClasses, StandaloneDeriving, TypeApplications #-}
import Prelude ()
import Control.Category.Constrained.Prelude
import qualified Control.Category.Hask as Hask
-- import Data.Constraint.Trivial
import Data.Foldable.Constrained
import Data.Map as M
import Data.Set as S
import qualified Data.Foldable as FL
main :: IO ()
main = print $ fmap (constrained @Ord (+1))
$ RMS ([(1,[11,21]),(2,[31,41])])
data RelationMS a b where
IdRMS :: RelationMS a a
RMS :: Map a (Set b) -> RelationMS a b
deriving instance (Show a, Show b) => Show (RelationMS a b)
instance Category RelationMS where
type Object RelationMS o = Ord o
id = IdRMS
RMS mp2 . RMS mp1
| M.null mp2 || M.null mp1 = RMS M.empty
| otherwise = RMS $ M.foldrWithKey
(\k s acc -> M.insert k (S.foldr (\x acc2 -> case M.lookup x mp2 of
Nothing -> acc2
Just s2 -> S.union s2 acc2
) S.empty s
) acc
) M.empty mp1
(°) :: (Object k a, Object k b, Object k c, Category k) => k a b -> k b c -> k a c
r1 ° r2 = r2 . r1
instance (Ord a, Ord b) => Semigroup (RelationMS a b) where
RMS r1 <> RMS r2 = RMS $ M.foldrWithKey (\k s acc -> M.insertWith S.union k s acc) r1 r2
instance (Ord a, Ord b) => Monoid (RelationMS a b) where
mempty = RMS M.empty
mappend = (<>)
instance Functor (RelationMS a) (ConstrainedCategory (->) Ord) Hask where
fmap (ConstrainedMorphism f) = ConstrainedMorphism $
\(RMS r) -> RMS $ M.map (S.map f) r
fldl :: (a -> Set b -> a) -> a -> RelationMS k b -> a
fldl f acc (RMS r) = M.foldl f acc r
fldMp :: Monoid b1 => (Set b2 -> b1) -> RelationMS k b2 -> b1
fldMp m (RMS r) = M.foldr (mappend . m) mempty r
-- instance Foldable (RelationMS a) (ConstrainedCategory (->) Ord) Hask where
-- foldMap f (RMS r)
-- | M.null r = mempty
-- | otherwise = FL.foldMap f r
-- ffoldl f = uncurry $ M.foldl (curry f)
You need
FL.foldMap (FL.foldMap f) rin your definition so that you fold over theMapand theSet.However, there's a critical error in your
Functorinstance; yourfmapis partial. It's not defined onIdRMS.I suggest using
-Wallto have the compiler warn you about such issues.The problem comes down to you need to be able to represent relations with finite and infinite domains.
IdRMS :: RelationRMS a acan already be used to represent some relations of infinite domain, it isn't powerful enough to represent a relation likefmap (\x -> [x]) IdRMS.One approach is to use
Map a (Set b)for finite relations anda -> Set bfor infinite relations.This changes the category instance accordingly:
And now you can define a total
Functorinstance:But a new issue raises its head when defining the
Foldableinstance:We have
f :: b -> mandg :: a -> Set b.Monoid mgives usappend :: m -> m -> m, and we knowOrd a, but in order to generate all thebvalues in the image of the relation, we need all the possibleavalues!One way you could try to salvage this is to use
BoundedandEnumas additional constraints on the relation's domain. Then you could try to enumerate all the possibleavalues with[minBound..maxBound](this may not be list every value for all types; I'm not sure if that's a law forBoundedandEnum).