Ich arbeite an einem anwendungsspezifischen Funktor, der ein Monoid enthält, um die Ausführung zu "sehen". Manchmal interessiert mich dieser Teil überhaupt nicht, daher ist die Wahl des Monoids irrelevant, da er niemals konsumiert wird. Ich habe vereinfacht, was ich habe in:Verwenden von Constraint-Typen und Typfamilien mit 'begrenzten' Constraints
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE TypeFamilies #-}
import GHC.Exts
class Render a b where render :: a -> b
instance Render a() where render = const()
class Merge a where
type Renderer a b :: Constraint
merge :: Renderer a b => a -> b
data Foo = Foo Bool
instance Merge Foo where
type (Renderer Foo) m = (Render Bool m)
merge (Foo b) = render b
Render
verwendet wird, um verschiedene a
s in einem einzigen b
zu verwandeln. Merge
ist eine große Vereinfachung meiner eigentlichen Funktor, aber der Punkt ist, enthält es eine Art Familie/Constraint und meine Absicht ist es, genau anzugeben, was Render
ers Merge
erfordert.
Nun, ich könnte auf „run“ wollen die Merge
, aber verwerfen die Ansicht, die so etwas wie verwandt ist:
runFoo :: Merge a => a -> Int
runFoo x = case merge x of() -> 5
Aber diese fehl, weil:
konnte nicht ableiten
(Renderer a())
aus einer Verwendung vonmerge
entstehen I ()
als meine Monoid gewählt, weil f orall a
, wir haben eine Instanz von Render a()
. Also, wenn es eine Möglichkeit gab zu sagen, dass Merge a
nur eine Sammlung Render
Einschränkungen bedeutet, dann würde dies gut funktionieren. Natürlich ist Merge a
allgemeiner als das - es könnte beliebige Einschränkungen hinzufügen, was den Kompilierungsfehler erklärt.
Gibt es trotzdem zu erreichen, was ich will ohne die Signatur von runFoo
ändern?
Hat 'Renderer' immer auch genau ein' Render'? –
@Tinctorius - Nein, hängt im Allgemeinen von der Anzahl der verschiedenen Typen in den Feldern von 'Foo' ab. – ocharles
Gibt es einen Grund, warum' Merge' nicht auch 'b' als Parameter hat? –