Skip to content

Commit 98614c0

Browse files
committed
Linear semigroups and monoids
1 parent 12cb80a commit 98614c0

File tree

4 files changed

+110
-0
lines changed

4 files changed

+110
-0
lines changed

linear-base.cabal

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ library
2323
Control.Optics.Linear.Internal
2424
Data.Bifunctor.Linear
2525
Data.Functor.Linear
26+
Data.Semigroup.Linear
2627
Data.Vector.Linear
2728
Data.Profunctor.Linear
2829
Data.Profunctor.Kleisli.Linear

src/Data/Functor/Linear.hs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@
1515
module Data.Functor.Linear where
1616

1717
import Prelude.Linear.Internal.Simple
18+
import Prelude (Maybe(..), Either(..))
1819
import Data.Functor.Const
20+
import Data.Semigroup.Linear
1921

2022
class Functor f where
2123
fmap :: (a ->. b) -> f a ->. f b
@@ -74,3 +76,23 @@ instance Traversable [] where
7476

7577
instance Functor (Const x) where
7678
fmap _ (Const x) = Const x
79+
80+
-- Const is only a traversable if the applicative is changed to a control
81+
-- applicative
82+
-- maybe that's the right definition?
83+
84+
instance Monoid x => Applicative (Const x) where
85+
pure _ = Const mempty
86+
Const x <*> Const y = Const (x <> y)
87+
88+
instance Functor Maybe where
89+
fmap _ Nothing = Nothing
90+
fmap f (Just x) = Just (f x)
91+
92+
instance Traversable Maybe where
93+
sequence Nothing = pure Nothing
94+
sequence (Just x) = fmap Just x
95+
96+
instance Functor (Either e) where
97+
fmap _ (Left x) = Left x
98+
fmap f (Right x) = Right (f x)

src/Data/Semigroup/Linear.hs

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
{-# LANGUAGE DerivingVia #-}
2+
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
3+
{-# LANGUAGE LinearTypes #-}
4+
{-# LANGUAGE NoImplicitPrelude #-}
5+
{-# LANGUAGE StandaloneDeriving #-}
6+
7+
-- | = The linear semigroup hierarchy
8+
--
9+
-- TODO: documentation
10+
11+
module Data.Semigroup.Linear
12+
( Semigroup(..)
13+
, Monoid(..)
14+
, LEndo(..), appLEndo
15+
, module Data.Semigroup
16+
)
17+
where
18+
19+
import Prelude.Linear.Internal.Simple
20+
import Data.Semigroup hiding (Semigroup(..))
21+
import qualified Data.Semigroup as Prelude
22+
import qualified Prelude
23+
import qualified Unsafe.Linear as Unsafe
24+
25+
class Prelude.Semigroup a => Semigroup a where
26+
(<>) :: a ->. a ->. a
27+
28+
class (Semigroup a, Prelude.Monoid a) => Monoid a where
29+
{-# MINIMAL #-}
30+
mempty :: a
31+
mempty = mempty
32+
-- convenience redefine
33+
34+
---------------
35+
-- Instances --
36+
---------------
37+
38+
instance Semigroup () where
39+
() <> () = ()
40+
41+
newtype LEndo a = LEndo (a ->. a)
42+
43+
-- TODO: have this as a newtype deconstructor once the right type can be
44+
-- correctly inferred
45+
appLEndo :: LEndo a ->. a ->. a
46+
appLEndo (LEndo f) = f
47+
48+
instance Prelude.Semigroup (LEndo a) where
49+
LEndo f <> LEndo g = LEndo (f . g)
50+
instance Prelude.Monoid (LEndo a) where
51+
mempty = LEndo id
52+
instance Semigroup (LEndo a) where
53+
LEndo f <> LEndo g = LEndo (f . g)
54+
instance Monoid (LEndo a) where
55+
56+
instance (Semigroup a, Semigroup b) => Semigroup (a,b) where
57+
(a,x) <> (b,y) = (a <> b, x <> y)
58+
instance (Monoid a, Monoid b) => Monoid (a,b)
59+
60+
instance Semigroup a => Semigroup (Dual a) where
61+
Dual x <> Dual y = Dual (y <> x)
62+
instance Monoid a => Monoid (Dual a)
63+
64+
newtype LWrap a = LWrap a
65+
deriving (Prelude.Semigroup, Prelude.Monoid)
66+
67+
-- This instance is unsafe: do not export LWrap so it cannot be used.
68+
instance Prelude.Semigroup a => Semigroup (LWrap a) where
69+
LWrap a <> LWrap b = LWrap (Unsafe.toLinear2 (Prelude.<>) a b)
70+
instance Prelude.Monoid a => Monoid (LWrap a)
71+
72+
-- XXX: I think these are safe but I'm not fully confident
73+
deriving via (LWrap (Sum a)) instance Prelude.Num a => Semigroup (Sum a)
74+
deriving via (LWrap (Sum a)) instance Prelude.Num a => Monoid (Sum a)
75+
deriving via (LWrap (Product a)) instance Prelude.Num a => Semigroup (Product a)
76+
deriving via (LWrap (Product a)) instance Prelude.Num a => Monoid (Product a)
77+
78+
-- Bools are movable so this is fine
79+
deriving via LWrap All instance Semigroup All
80+
deriving via LWrap All instance Monoid All
81+
deriving via LWrap Any instance Semigroup Any
82+
deriving via LWrap Any instance Monoid Any

src/Prelude/Linear.hs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ module Prelude.Linear
1919
, either
2020
, maybe
2121
, forget
22+
, Semigroup(..)
23+
, Monoid(..)
2224
-- * Unrestricted
2325
-- $ unrestricted
2426
, Unrestricted(..)
@@ -37,6 +39,7 @@ module Prelude.Linear
3739
, module Prelude
3840
) where
3941

42+
import Data.Semigroup.Linear
4043
import qualified Data.Functor.Linear as Data
4144
import Data.Vector.Linear (V)
4245
import qualified Data.Vector.Linear as V
@@ -56,6 +59,8 @@ import Prelude hiding
5659
, Applicative(..)
5760
, Monad(..)
5861
, Traversable(..)
62+
, Semigroup(..)
63+
, Monoid(..)
5964
)
6065
import Prelude.Linear.Internal.Simple
6166
import qualified Unsafe.Linear as Unsafe

0 commit comments

Comments
 (0)