Hacktoberfest 2026:维护者为十月标记出来的 issue,仍然开放、适合新手。 浏览 Hacktoberfest issue

Use of (lawless) Group/monoid-subclasses/InverseSemigroup in view

未关闭
#37 9 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看

还没有人认领这个 Issue。

评估

难度
5/5
预计耗时
一周以上
新手友好度
18/100
Issue 类型
重构
描述清晰度
需要澄清
活跃度
停滞
技术栈
haskell
领域
tooling

调研方向

No files or tests are named. Start by inspecting the current Group and MonoidalMap instances in patch, then resolve whether the project should adopt InverseSemigroup or use monoid-subclasses; done means the chosen approach supports lawful Patch-related instances and has its laws and behavior verified.

由索引模型根据 Issue 内容生成。

描述

Continuing https://github.com/Taneb/groups/issues/7#issuecomment-1006968329 in a more appropriate place:

Context: patch currently provides (but does not directly use) a Group class with lawless instance (Ord k, Group g) => Group (MonoidalMap k g). (let x = fromList [(1, y)] in x ~~ x evaluates to fromList [(1, mempty)] instead of mempty.) I'm sure that something downstream is using this class to provide efficient Patch instances or something.

Context: patch, groups, group-theory (via reexport from groups), and monoid-subclasses all provide a class that requires (<>) to be commutative. Some as a subclass of Semigroup, some as a subclass of their Group.

There are two options:

Option 1 - Create (here or elsewhere) and use an InverseSemigroup class

Since it can have lawful instance (Ord k, InverseSemigroup g) => InverseSemigroup (MonoidalMap k g):

class Semigroup g => InverseSemigroup g where
  -- Laws:
  -- x <> inv x <> x = x
  -- inv x <> x <> inv x = x
  -- inverses are unique
  -- All idempotents commute
  -- All idempotents have the from y = x <> inv x for some x
  inv :: g -> g

  (~~) :: g -> g -> g
  pow :: Integral n => g -> n -> g

-- For -XDerivingVia
newtype ViaGroup g = ViaGroup g
instance Group g => InverseSemigroup (ViaGroup g)
Option 2 - Write Patch instances using monoid-subclasses instead

monoid-subclasses has class (Commutative m, LeftReductive m, RightReductive m) => Reductive m (and similar for Cancellative), and they may get you what you want. Some thoughts:

  • Reductive provides an operator (</>) :: Reductive m => m -> m -> Maybe m;
  • Cancellative adds two additional laws to (</>):
    • (a <> b) </> a == Just b
    • (a <> b) </> b == Just a
  • You can't recover an inversion operation from Cancellative alone, as you can't be certain of isJust (mempty </> x). (Consider instance Cancellative Natural.)
    • Every finite cancellative monoid is a group, but this might not be useful.
  • Instance Cancellative m => Cancellative (MonoidalMap k m) smells like it would be lawful:
    instance (Ord k, Commutative m) => Commutative (MonoidalMap k m)
    
    instance (Ord k, LeftReductive m) => LeftReductive (MonoidalMap k m) where
      stripPrefix (MonoidalMap prefix) (MonoidalMap m) =
        MonoidalMap
          <$> mergeA
            (traverseMissing $ \_ _ -> Nothing)
            (traverseMissing $ const pure)
            (zipWithAMatched $ \_ pf v -> stripPrefix pf v)
            prefix
            m
    
    instance (Ord k, RightReductive m) => RightReductive (MonoidalMap k m) where
      stripSuffix (MonoidalMap suffix) (MonoidalMap m) =
        MonoidalMap
          <$> mergeA
            (traverseMissing $ \_ _ -> Nothing)
            (traverseMissing $ const pure)
            (zipWithAMatched $ \_ sf v -> stripSuffix sf v)
            suffix
            m
    
    instance (Ord k, Reductive m) => Reductive (MonoidalMap k m) where
      MonoidalMap x </> MonoidalMap y =
        MonoidalMap
          <$> mergeA
            (traverseMissing $ \_ _ -> Nothing)
            (traverseMissing $ \_ _ -> Nothing)
            (zipWithAMatched $ const (</>))
            x
            y
    
    instance (Ord k, LeftCancellative m) => LeftCancellative (MonoidalMap k m)
    instance (Ord k, RightCancellative m) => RightCancellative (MonoidalMap k m)
    instance (Ord k, CancellativeMonoid m) => Cancellative (MonoidalMap k m)
    
  • This may be enough for your uses of patch - instead of computing the inverse of a patch, instead attempt to unapply it directly?
  • If you need to send data structures across a network boundary, you could do this using [Either m m], like the free group in free-algebras.
  • If that's not enough, then I think you probably need to build your patch-using stuff atop a new InverseSemigroup class.
  • I'm very interested to hear what you end up doing here, and if you do make a minimal package providing class Semigroup m => Commutative m, let me know so I can help PR monoid-subclasses, monoidal-containers, etc.
主要语言
Haskell
星标
17
派生
16
PR 合并指标
30 天内没有已合并 PR

环境准备

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

reflex-frp/patch 的其他 Issue

查看 reflex-frp/patch 的全部 Issue

相似的 Issue

更多 Haskell Issue

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。