2
votes

Say I have the following type class

class Silly (t :: * -> *) where
    -- details

I would like to be able to express the following constraint, but I'm not sure if it is even possible.

class (Silly s) => Willy (s t) where
    -- details

Basically I want to put a constraint on the type constructor, not the entire type. Is this even expressible? I'm not even sure what this kind of constraint would be called, so Google has been no help.

EDIT: I have a data type

data Reasoner logic atoms a = Reasoner { unReasoner :: MassAssignment atoms -> a }

that has an Applicative instance. I initially had a run function in order to make working with these Reasoners a bit easier, but since I want to take advantage of the free composability of applicatives, I defined a type class containing run instead, ala

class RunReasoner r where
    type MassType r
    type ResultType r
    run :: r -> MassType r -> ResultType r

with the following instances

instance RunReasoner (Reasoner l as a) where
    type MassType (Reasoner l as a) = MassAssignment as
    type ResultType (Reasoner l as a) = a
    run = -- details

instance (RunReasoner (r2 t)) => RunReasoner (Compose (Reasoner l1 as1) r2 t) where
    type MassType (Compose (Reasoner l1 as1) r2 t) = MassAssignment as1
    type ResultType (Compose (Reasoner l1 as1) r2 t) = r2 t
    run = -- details

so that I can write code such as

expression `run` mass1 `run` mass2 `run` ... `run` massN

This is all good for the most part, but I am now composing reasoners in other ways, and would prefer if the MassType were available from just the type constructor Reasoner l as, instead of having to have the full type instance Reasoner l as a. Therefore I was considering splitting the RunReasoner type class into two, since MassType does not depend on the final type parameter.

1
Could you give some more context on how you intend to use this? I'm pretty sure it's possible to achieve what you need quite simply, though it won't look like what you've written.leftaroundabout

1 Answers

5
votes

You could make a standalone type family

type family MassType (r :: * -> *)
type instance MassType (Reasoner l as) = as