首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何定义Data.Foldable.Constrained的实例?

如何定义Data.Foldable.Constrained的实例?
EN

Stack Overflow用户
提问于 2019-06-06 17:56:08
回答 1查看 105关注 0票数 1

我成功地定义了范畴,函子,半群,单样约束。现在我被Data.Foldable.Constrained困住了。更确切地说,我似乎正确地定义了不受约束的函数fldl和fldMp,但我无法让它们被接受为Foldable.Constrained实例。我的定义尝试作为注释插入。

代码语言:javascript
复制
{-# 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)
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-06-06 22:37:43

您需要在定义中使用FL.foldMap (FL.foldMap f) r,这样就可以在MapSet上折叠起来。

但是,Functor实例中存在一个关键错误;您的fmap是部分的。它没有在IdRMS上定义。

我建议使用-Wall让编译器警告您这类问题。

问题归结到你需要能够表示与有限和无限域的关系。IdRMS :: RelationRMS a a已经可以用来表示无限域的一些关系,但是它还不够强大,不能表示像fmap (\x -> [x]) IdRMS这样的关系。

一种方法是将Map a (Set b)用于有限关系,a -> Set b用于无限关系。

代码语言:javascript
复制
data Relation a b where
   Fin :: Map a (Set b) -> Relation a b
   Inf :: (a -> Set b) -> Relation a b

image :: Relation a b -> a -> Set b
image (Fin f) a = M.findWithDefault (S.empty) a f
image (Inf f) a = f a

这相应地更改了类别实例:

代码语言:javascript
复制
instance Category Relation where
  type Object Relation a = Ord a

  id = Inf S.singleton

  f . Fin g = Fin $ M.mapMaybe (nonEmptySet . concatMapSet (image f)) g
  f . Inf g = Inf $ concatMapSet (image f) . g

nonEmptySet :: Set a -> Maybe (Set a)
nonEmptySet | S.null s = Nothing
            | otherwise = Just s

concatMapSet :: Ord b => (a -> Set b) -> Set a -> Set b
concatMapSet f = S.unions . fmap f . S.toList

现在您可以定义一个完整的Functor实例:

代码语言:javascript
复制
instance Functor (Relation a) (Ord ⊢ (->)) Hask where
  fmap (ConstrainedMorphism f) = ConstrainedMorphism $ \case -- using {-# LANGUAGE LambdaCase #-}
    Fin g -> Fin $ fmap (S.map f) g
    Inf g -> Inf $ fmap (S.map f) g

但是,在定义Foldable实例时,一个新的问题引起了人们的注意:

代码语言:javascript
复制
instance Foldable (Relation a) (Ord ⊢ (->)) Hask where
  foldMap (ConstrainedMorphism f) = ConstrainedMorphism $ \case
    Fin g -> Prelude.foldMap (Prelude.foldMap f) g
    Inf g -> -- uh oh...problem!

我们有f :: b -> mg :: a -> Set bMonoid m给我们append :: m -> m -> m,我们知道Ord a,但是为了生成关系图像中的所有b值,我们需要所有可能的a值!

您可以尝试挽救的一种方法是使用BoundedEnum作为关系域上的附加约束。然后,您可以尝试用[minBound..maxBound]枚举所有可能的[minBound..maxBound]值(这可能不是列出所有类型的所有值;我不确定这是否是BoundedEnum的规律)。

代码语言:javascript
复制
instance (Enum a, Bounded a) => Foldable (Relation a) (Ord ⊢ (->)) Hask where
  foldMap (ConstrainedMorphism f) = ConstrainedMorphism $ \case
    Fin g -> Prelude.foldMap (Prelude.foldMap f) g
    Inf g -> Prelude.foldMap (Prelude.foldMap f . g) [minBound .. maxBound]
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/56482798

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档