2016-08-14 4 views
2

Ich habe die nächsten Strukturen:Allgemein Typ in einer Liste von Funktionen

data BasicTypes = TypeS String 
       | TypeI Integer 
       deriving (Show, Ord, Eq) 

data MRF = MRF { 
    lastValue :: BasicTypes, 
    requestedFilters :: [RF] 
} deriving (Show) 

data RF = RF { 
    event :: String, 
    filters :: [Filter] 
} deriving (Show) 

type BooleanFunction a = a -> Bool 
data Filter = Filter { 
    operation :: BooleanFunction BasicTypes, 
    value :: BasicTypes 
} deriving (Show) 

ich ein MRF Daten haben wollen, die eine Liste von requestedFilters (RF) enthält. Jede RF hat Filter, und diese Filter können vom Typ String oder Integer sein.

Die Sache ist, dass die Filter dynamisch erstellt werden und kann entweder über einen String oder ein Integer-Wert sein, so konnten wir haben:

Filter1 = Filter {operation = (==) 5, value = 3} 
Filter2 = Filter {operation = (==) "hello", value = "hello"} 

Und beide Filter in der gleichen MRF aufgenommen worden!

Ich mag die BasicTypes Daten zu vermeiden, und eine generische Art setzen, aber wenn ein Put operation :: a -> Bool dann alle Filter vom gleichen Typ sein sollten (so kann ich nicht Dinge wie Integer -> Bool und String -> Bool zusammen in der gleichen Liste).

Was schlagen Sie vor? Vielen Dank!

PS: Ich habe bereits mit dem Typ TypeRep versucht, aber ich konnte keine Lösung für dieses

+0

Und was passiert, wenn 'Filter1' auf einen String oder' Filter2' auf einen Integer angewendet wird? Es macht keinen Sinn, eine heterogene Liste von Filtern zu haben. –

Antwort

2

Hat diese Arbeit für Sie?

data Filter a = Filter { operation :: a -> Bool, value :: a } 

data RF a = RF { event :: String; filters :: [ Filter a ] } 

data MRF a = MRF { lastValue :: a, requestedFilters :: [RF a] } 

In einem RF a, alle Filter haben Filter a vom Typ sein.

aktualisiert

ich eine Liste von Filtern für Strings in einem RF haben will, dann mit einer Liste von Integer einem anderen RF, dann andere RF mit einer Liste von Floats, und so weiter. Und ich möchte all diese RF in einer Liste (MRF).

Wie dies etwa:

data MFRList = MRFList 
      { integerMRFs :: [ MRF Integer ] 
      , stringMRFs  :: [ MRF String ] 
      , floatMRFs  :: [ MRF Float ] 
      } 

so viele Felder hinzufügen, wie Sie benötigen.

+0

Ok, aber in der MRF kann ich RFs mit verschiedenen Filtern haben? – dani24

+0

Die eigentliche Frage ist, was wollen Sie mit einer MRF tun? Was erwarten Sie, wenn Sie versuchen, einen Filter für Ganzzahlen auf eine Zeichenfolge anzuwenden? Können Sie zeigen, was Sie in einer anderen Sprache erreichen möchten? – ErikR

+0

Ich möchte eine Liste von Filtern für Strings in einer RF haben, dann eine andere RF mit einer Liste von Integer, dann andere RF mit einer Liste von Floats, und so weiter. Und ich möchte all diese RF in einer Liste (MRF). Das gibt den MRF-Daten Flexibilität in der Eingabe, bin ich klar? Wenn ich das mache, was Sie vorschlagen, dann habe ich eine MRF mit einer Liste von nur einem Typ:/ Haben Sie eine andere Idee? – dani24

1

Die grundlegende Lösung ist zwei Konstruktoren für Filter zu verwenden:

data Filter 
    = FilterI { 
    operationI :: Int -> Bool, 
    valueI :: Int 
    } 
    | FilterS { 
    operationS :: String -> Bool, 
    valueS :: String 
    } 

eine fortschrittlichere Alternative GADTs mit:

-- singleton 
data BasicType t where 
    BasicI :: BasicType Int 
    BasicS :: BasicType String 

data Filter where 
    Filter :: 
     { ty :: BasicType t 
     , operation :: t -> Bool 
     , value :: t 
     } -> Filter 

Beachten Sie, dass oben ist es wichtig, dass das Feld ty kann zur Laufzeit getestet werden, damit wir feststellen können, welcher Typ t tatsächlich ist. Beispiel:

useFilter :: Filter -> Int 
useFilter (Filter BasicI op v) = v   -- we know it's Int 
useFilter (Filter BasicS op v) = length v -- we know it's String 

Wir könnten auch GADTs vermeiden und schlicht existentielle Typen verwenden, nur:

data Filter where 
    Filter :: 
     { operation :: t -> Bool 
     , value :: t 
     } -> Filter 

aber auf diese Weise Filter ist eigentlich isomorph Bool: Es gibt nichts, was wir mit value tun können, es sei denn, Verwenden Sie es als Argument für Filter. Daher ist hier eine Liste von Filtern einfach eine Liste von Booleschen Werten, was uninteressant ist.

Wenn Sie eine Liste existenzieller Typen verwenden, verwenden Sie möglicherweise eine bekannte antipattern.

Verwandte Themen