2010-07-23 10 views
5

Ich bin ein Hakerk Neuling und ich konnte keine Antwort auf diese Frage finden.Haskell: Benutzerdefinierte Typen mit Bedingungen

Können wir Typen mit Bedingungen definieren? Zum Beispiel einfache benutzerdefinierte Datentyp wäre:

data MyList = MyList [a] 

Kann ich irgendwie diesen Code ändern, so MyList Konstruktor nur Listen mit einer geraden Anzahl von Elementen nehmen? Etwas wie

data MyList = MyList [a] where (even (length a)) 

Vielen Dank!

+3

'Daten MyList = Liste (a, a)'? –

+0

Alexandre, ist das nicht erlaubt Liste ([], []), Liste ([1], []), Liste ([1,2,3], [1,2]) die nicht gerade sind, obwohl sie haben 2 gültige Elemente? – Alex

+1

Alexandre meinte Listen von Tupeln: [(a, a)]. Auf diese Weise haben Sie eine gerade Zahl von a, wie [(1,2), (5,2), (2,10)]. – sdcvvc

Antwort

7

Nein, das geht nicht.

Wenn es wirklich notwendig ist, schreiben Sie einfach eine Konstruktor-ähnliche Funktion.

toMyList :: [a] -> MyList 
toMyList l | even (length l) = MyList l 
      | otherwise  = error "Length of list has to be even" 

oder wenn Fehlerprüfung wird wahrscheinlich auftreten: auf dem Anwendungsfall

toMyList :: [a] -> Maybe MyList 

Aber je, vielleicht können Sie sich durch Arten ausdrücken (zB Tupel oder zwei Listen) als durch runtime- Kontrollen.

+0

Vielen Dank! – Alex

3

könnten Sie so etwas wie verwenden

data MyList a = MyNil 
       | MyCons a a (MyList a) 

Dies stellt sicher, dass Ihre Liste zu einem Zeitpunkt mehr zwei Elemente bekommt. Dies entspricht Alexandres Kommentar, aber es lohnt sich, etwas genauer zu betrachten.

Zusammen mit einigen von/zu Konvertierungsfunktionen wie

fromMyList :: MyList a -> [a] 
fromMyList MyNil = [] 
fromMyList (MyCons x y rest) = x : y : fromMyList rest 

toMyList :: [a] -> Maybe (MyList a) 
toMyList [] = Just MyNil 
toMyList [_] = Nothing 
toMyList (x:y:rest) = fmap (MyCons x y) (toMyList rest) 

toMyListError :: [a] -> MyList a 
toMyListError [] = MyNil 
toMyListError [_] = error "Length of list has to be even" 
toMyListError (x:y:rest) = MyCons x y (toMyListError rest) 

-- these two may be a bit more difficult to use... 
fromMyListTuple :: MyList a -> [(a,a)] 
fromMyListTuple MyNil = [] 
fromMyListTuple (MyCons x y rest) = (x,y) : fromMyListTuple rest 

toMyListTuple :: [(a,a)] -> MyList a 
toMyListTuple = foldr (\(x,y) -> MyCons x y) MyNil  

wird es möglich, bestehende Liste Funktionen mit einem wenig Gedanken wieder zu verwenden:

myAppend :: MyList a -> MyList a -> MyList a 
myAppend xs ys = toMyListError (fromMyList xs ++ fromMyList ys) 

Aber das hängt alles davon ab, was Sie wirklich wollen mit diesen Listen zu tun haben!

Sie können auf diese Weise viele Eigenschaften der Anzahl der Elemente im Container angeben, siehe beispielsweise die Arbeit von Chris Okasaki. Andere Bedingungen könnten ebenfalls möglich sein, aber in den meisten Fällen ist es besser für Dario.

Aber schließlich, beachten Sie, dass, wenn Ihr Typ vollständig polymorph sein soll, Sie nicht wirklich viel mehr Informationen über die enthaltenen Listen als die Anzahl der Elemente darin verwenden können!

Verwandte Themen