2010-07-23 33 views
5

Soy un novato en Haskell y no he podido encontrar una respuesta a esta pregunta.Haskell: tipos personalizados con condiciones

¿Podemos definir tipos con condiciones? Por ejemplo, simple tipo de datos definido por el usuario sería:

data MyList = MyList [a] 

¿hay algún modo modificar este código para el constructor MyList puede tomar sólo las listas con número par de elementos? Algo así como

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

¡Gracias!

+3

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

+0

Alexandre, no es que permite Lista ([], []), Lista ([1], []), Lista ([1,2,3], [1,2]) que no son pares, a pesar de tener 2 elementos validos? – Alex

+1

Alexandre significaba listas de tuplas: [(a, a)]. De esta forma, tendrá un número par de a's, como [(1,2), (5,2), (2,10)]. – sdcvvc

Respuesta

7

No, no puedes.

Si es realmente necesario, solo escriba una función tipo constructor usted mismo.

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

o si es probable que se produzca la comprobación de errores:

toMyList :: [a] -> Maybe MyList 

Pero dependiendo del caso de uso, tal vez puede expresarse a través de tipos (por ejemplo, tuplas o dos listas) que a través de tiempo de ejecución- cheques.

+0

¡Muchas gracias! – Alex

3

Se podría utilizar algo como

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

Esto asegura que su lista se alarga dos elementos a la vez. Esto es equivalente al comentario de Alexandre, pero vale la pena analizarlo con cierto detalle.

Junto con algunos de/a la conversión funciones como

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  

se hace posible reutilizar las funciones de lista existentes con un poco de pensamiento:

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

Pero todo depende de lo que realmente quiere para hacer con estas listas!

Puede indicar muchas propiedades de la cantidad de elementos en el contenedor de esta manera, vea el trabajo de Chris Okasaki, por ejemplo. Otras condiciones podrían ser posibles también, pero en la mayoría de los casos estarás mejor con el enfoque de Darío.

Pero, por último, tenga en cuenta que si su tipo es ser completamente polimórfico, ¡no puede usar mucha más información sobre las listas contenidas que el número de elementos en ella de todos modos!

Cuestiones relacionadas