2010-07-23 18 views
5

Sono un principiante di haskell e non sono riuscito a trovare una risposta a questa domanda.Haskell: Tipi personalizzati con condizioni

Possiamo definire i tipi con condizioni? Ad esempio, semplice tipo di dati definito dall'utente potrebbe essere:

data MyList = MyList [a] 

Posso in qualche modo modificare il codice in modo costruttore MyList può prendere solo liste con numero pari di elementi? Qualcosa come

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

Grazie!

+3

'data MyList = Lista (a, a)'? –

+0

Alexandre, non è quello che consente Elenco ([], []), Elenco ([1], []), Elenco ([1,2,3], [1,2]) che non sono pari, nonostante abbia 2 elementi validi? – Alex

+1

Alexandre significava liste di tuple: [(a, a)]. In questo modo avrai un numero pari di a, come [(1,2), (5,2), (2,10)]. – sdcvvc

risposta

7

No, non è possibile.

Se è veramente necessario, basta scrivere una funzione simile al costruttore da solo.

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

o se il controllo degli errori è probabile che si verifichi:

toMyList :: [a] -> Maybe MyList 

Ma a seconda del caso d'uso, forse si può esprimersi attraverso i tipi (ad esempio tuple o due liste) che attraverso runtime- controlli.

+0

Grazie mille! – Alex

3

Si potrebbe usare qualcosa come

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

Questo fa in modo che la vostra lista si allunga di due elementi alla volta. Questo è equivalente al commento di Alexandre, ma vale la pena guardare in dettaglio.

Insieme ad alcuni da/per conversione funzioni come

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  

diventa possibile riutilizzare le funzioni di lista esistenti con un po 'di pensiero:

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

Ma che tutto dipende da quello che realmente vuole fare con queste liste!

È possibile dichiarare molte proprietà del numero di elementi nel contenitore in questo modo, vedere il lavoro di Chris Okasaki per esempio. Anche altre condizioni potrebbero essere possibili, ma nella maggior parte dei casi starai meglio con l'approccio di Dario.

Ma, infine, si noti che se il proprio tipo deve essere completamente polimorfico non è possibile utilizzare molte più informazioni sugli elenchi contenuti rispetto al numero di elementi in esso contenuti comunque!

Problemi correlati