Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 8745609
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: June 13, 20262026-06-13T12:03:30+00:00 2026-06-13T12:03:30+00:00

I have a data type that is an instance of Monoid so I can

  • 0

I have a data type that is an instance of Monoid so I can get nice values composition:

data R a = R String (Maybe (String → a))

instance Monoid (R a) where
  mempty = R "" Nothing
  R s f `mappend` R t g = R (s ++ t) (case g of Just _ → g; Nothing → f)

Next, I don’t want to combine all R a values with one another, it doesn’t make sense in my domain. So I introduce phantom type t:

{-# LANGUAGE DataKinds, KindSignatures #-}

data K = T1 | T2
data R (t ∷ K) a = R String (Maybe (String → a))

instance Monoid (R t a) where …

So I have “restricted” values:

v1 ∷ R T1 Int
v2 ∷ R T2 Int
-- v1 <> v2 => type error

and “unrestricted”:

v ∷ R t Int
-- v <> v1 => ok
-- v <> v2 => ok

But now I have a problem. When it comes to v30, for example:

  • I would have huge datakind declaration (data K = T1 | … | T30). I could solve by using type level naturals to get infinite source of phantom types (the cure is worse than the disease, isn’t it?)
  • I should remember which phantom type for what value to use when writing type signatures in dependent code (that is really annoying)

Is there an easier approach to restrict composition somehow?

  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-06-13T12:03:31+00:00Added an answer on June 13, 2026 at 12:03 pm

    Looking for the ConstrainedMonoid

    I came to a very similar problem lately, which I finally solved the way described at the end of this post (not involving a monoid, but using predicates on types). However, I took the challenge and tried to write a ConstrainedMonoid class.

    Here’s the idea:

    class ConstrainedMonoid m where
      type Compatible m (t1 :: k) (t2 :: k) :: Constraint
      type TAppend m (t1 :: k) (t2 :: k) :: k
      type TZero m :: k
    
      memptyC :: m (TZero m)
      mappendC :: (Compatible m t t') => m t -> m t' -> m (TAppend m t t')
    

    Ok, there’s the trivial instance, which in fact doesn’t add anything new (I swapped Rs type arguments):

    data K = T0 | T1 | T2 | T3 | T4
    data R a (t :: K) = R String (Maybe (String -> a))
    
    instance ConstrainedMonoid (R a) where
      type Compatible (R a) T1 T1 = ()
      type Compatible (R a) T2 T2 = ()
      type Compatible (R a) T3 T3 = ()
      type Compatible (R a) T4 T4 = ()
      type Compatible (R a) T0 y = ()
      type Compatible (R a) x T0 = ()
    
      type TAppend (R a) T0 y = y 
      type TAppend (R a) x T0 = x
      type TAppend (R a) T1 T1 = T1
      type TAppend (R a) T2 T2 = T2
      type TAppend (R a) T3 T3 = T3
      type TAppend (R a) T4 T4 = T4
      type TZero (R a) = T0
    
      memptyC = R "" Nothing
      R s f `mappendC` R t g = R (s ++ t) (g `mplus` f)
    

    This unfortunately takes a lot of redundant type instances (OverlappingInstances don’t seem to work for type families), but I think it satisfies the monoid laws, at type level as well as at value level.

    However, it is not closed. It’s more like a set of different monoids, indexed by K. If that’s what you want, it should suffice.

    If you want more

    Let’s look at a different variant:

    data B (t :: K) = B String deriving Show
    
    instance ConstrainedMonoid B where
      type Compatible B T1 T1 = ()
      type Compatible B T2 T2 = ()
      type Compatible B T3 T3 = ()
      type Compatible B T4 T4 = ()
    
      type TAppend B x y = T1
      type TZero B = T3 
    
      memptyC = B ""
      (B x) `mappendC` (B y) = B (x ++ y)
    

    This could be a case which makes sense in your domain — however, it is not a monoid anymore. And if you tried to make one of it, it’ll get the same as the instance above, just with different TZero. I’m actually just speculating here, but my intuition tells me that the only valid monoid instances are exactly the ones like for R a; only with different unit values.

    Otherwise, you’ll end up with something not neccessarily associative (and probably with a terminal object, I think), which is not closed under composition. And if you want to restrict composition to equal Ks, you’ll lose the unit value.

    A better way (IMHO)

    Here’s how I actually solved my problem (I didn’t even think of monoids back then, since they didn’t make sense anyhow). The solution essentially strips off everything except the Compatible “constraint producer”, which is left as a predicate on two types:

    type family Matching (t1 :: K) (t2 :: K) :: Constraint
    type instance Matching T1 T1 = ()
    type instance Matching T2 T1 = ()
    type instance Matching T1 T2 = ()
    type instance Matching T4 T4 = ()
    

    used like

    foo :: (Matching a b) => B a -> B b -> B Int
    

    This gives you full control over your definition of compatibility, and what kind of composition (not necessarily monoidal) you want, and it is more general. It can be expanded to infinite kinds, too:

    -- pseudo code, but you get what I mean
    type instance NatMatching m n = (IsEven m, m > n)
    

    Answering your two last points:

    • Yes, you have to define sufficiently many types in your kind. But I think that they should be self-explaining anyway. You could also split up them into groups, or define a recursive type.

    • You mainly have to remind the meaning of the index type at two places: the definition of the constraint, and maybe for factory methods (mkB1 :: String -> B T1). But I think that shouldn’t be the problem, if the types are named well. (It can be very redundant, though — I’ve not found a way to avoid that yet. Probably TH would work.)

    Could this be easier?

    What I’d actually like to be able to write is the following:

    type family Matching (t1 :: K) (t2 :: K) :: Constraint
    type instance Matching T1 y = ()
    type instance Matching x T1 = ()
    type instance Matching x y = (x ~ y)
    

    I fear this has a serious reason not to be allowed; however, maybe, it’s just not implemented…

    EDIT: Nowadays, we have closed type families, which do exactly this.

    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

I have a class State that has a string data type called moveType .
I have: data type (all types are values types) as string (for example: 'System.Boolean'
I have a data type that contains a set and a method that expects
I know that SQL Server does not have boolean data type and your best
When defining parameter type that is e.g. in System.Data you have no intellisense and
I have a simple function that looks at an incoming mySQL data type and
I have a generic linked-list that holds data of type void* I am trying
Are there any standalone type conversion libraries? I have a data storage system that
I have a Web Service call that returns reporting data using Linq-To-Entity (strongly type
I have a Haskell record data type that looks like this: data Client =

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.