简体   繁体   中英

Relation between the Semigroupoid and Semigroup classes

In the last week I've been trying to grasp some of Haskell's "core" types and type classes (but have been studying Haskell for at most two weeks total), and I've found something that bugs me:

  • a "Semigroupoid" is a generalization of a "Category", meaning that any Category is trivially a Semigroupoid, just by ignoring it's own identity and defining

o = (.)

  • also a "Semigroup" is a generalization of a "Monoid", in the exact same connotation as above: one just has to ignore mempty and define

(<>) = mappend

These two facts alone, and the idea that both Semigroupoids and Semigroups only have a notion of combining elements (semigroupoid-composition vs semigroup-multiplication) and both Category and Monoid also have a notion of "unity" (identity vs unit element) bring to mind that one could express relations between Semigroupoids and Semigroups, and between Categories and Monoids as follows

import Prelude hiding (id, (.))

import Data.Semigroupoid
import Data.Semigroup

import Control.Category
import Data.Monoid

instance Semigroupoid c => Semigroup (c a a) where
    (<>) = o

instance Category c => Monoid (c a a) where
    mempty = id
    mappend = (.)

main = putStrLn "Does not type-check!"

Now, I'm not sure why this doesn't compile; the ghc compiler says:

All instance types must be of the form (T a1 ... an)
where a1 ... an are *distinct type variables*,
and each type variable appears at most once in the instance head.

but it happens that including

{-# LANGUAGE FlexibleInstances #-}

on top of the file fixes everything.

The relations expressed above don't seem to be built in the libraries, while the relations between Semigroupoid and Category, and between Semigroup and Monoid are be built in.

Is there any specific reason for this, and I'm just missing it?

Maybe it has something to do with the mysterious "FlexibleInstances"?

Any insight would be greatly appreciated.

If it only required FlexibleInstances nobody would mind (that extension is totally harmless), but unfortunately it also leads to requiring a very un-harmless other extension as soon as you add sufficiently interesting other instances. Namely,

{-# LANGUAGE FlexibleInstances #-}

import Control.Category (Category)

instance Category c => Monoid (c a a)

data Nontrivial s q = Nontrivial {
      someLabel :: String
    , someValues :: [(s, Int)]
    , otherValues :: Maybe (String, q)
    , moreStuff :: ({-...-})
    }

instance (Monoid s, Monoid q) => Monoid (Nontrivial s q) where
  mempty = Nontrivial "" [] Nothing ()

main = case mempty :: Nontrivial String String of
  Nontrivial _ _ _ _ -> return ()

does not compile:

$ runhaskell  wtmpf-file6064.hs 

wtmpf-file6064.hs:17:13:
    Overlapping instances for Monoid (Nontrivial String String)
      arising from a use of ‘mempty’
    Matching instances:
      instance Category c => Monoid (c a a)
        -- Defined at wtmpf-file6064.hs:5:10
      instance (Monoid s, Monoid q) => Monoid (Nontrivial s q)
        -- Defined at wtmpf-file6064.hs:14:10
    In the expression: mempty :: Nontrivial String String
    In the expression:
      case mempty :: Nontrivial String String of {
        Nontrivial _ _ _ _ -> return () }
    In an equation for ‘main’:
        main
          = case mempty :: Nontrivial String String of {
              Nontrivial _ _ _ _ -> return () }

Now, you could get it working by adding {-# OVERLAPPABLE #-} Pragmas , but this is some rather fiddly business and can lead to strange behaviour. Such instances are strongly avoided.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM