2011-08-01 17 views
5

tengo un registro en un documento que utilice dos IntMaps:¿Cómo se usa IntMap con diferentes tipos de claves?

data Doc = Doc { kernels :: IntMap Kernel, nodes :: IntMap Node } 

pero he encontrado que las claves de ambos IntMaps tienen un significado diferente y no llego a separar en dos tipos diferentes y no consigo errores cuando mezcla tipos de kernel y tipos de nodos Quiero tener funciones que comprueben las claves del mapa del kernel y los mapas de nodos y no permita la confusión. Por ejemplo:

someFunction :: Doc -> KernelKey -> NodeKey -> a 
someFunction doc k1 k2 = ..... 

En lugar de la corriente:

someFunction :: Doc -> Int -> Int -> a 
someFunction doc k1 k2 = .... -- warning check twice k1 and k2 

personal ¿Se Posible? O cambiaré de IntMap a Map.

Gracias

+1

¿Cuál es su razón para usar 'IntMap' en lugar de' Map'? Si se trata de rendimiento, entonces debe considerar 'contenedores no ordenados' (que podría ser la mejor solución para usted, pero vale la pena considerar). –

+2

Consulte también la pregunta relacionada sobre 'IntSet' http://stackoverflow.com/questions/5746590/how-to-newtype-intset ... podría echarle un vistazo al paquete [' enummapset'] (http://hackage.haskell.org/package/enummapset), que es lo que estoy usando actualmente – hvr

Respuesta

10

Puede utilizar newtype para hacer envolturas alrededor Int para distinguir su significado.

newtype KernelKey = KernelKey Int 
newtype NodeKey = NodeKey Int 

someFunction :: Doc -> KernelKey -> NodeKey -> a 
someFunction doc (KernelKey k1) (NodeKey k2) = ... 

De esta forma, podrá seguir usando IntMap internamente, sino exponer una interfaz más de tipo seguro, especialmente si también controlar cómo se crean los valores KernelKey y NodeKey, es decir, no se exporten sus constructores para que los usuarios solo obténgalos como valores de retorno de sus otras funciones.

Tenga en cuenta que las envolturas newtype desaparecen en tiempo de ejecución, por lo que este envoltorio adicional y su desenvolvimiento no afectan el rendimiento de ninguna manera.

+0

Estaba confundido sobre el rendimiento. Pero si el envoltorio desaparece en el tiempo de ejecución, usaré tu solución. – Zhen

3

Puede crear un tipo de clave unificada y ajustar la API de IntMap para su tipo de documento. Puede parecerse a esto.

data DocValue = DocKernel Kernel 
       | DocNode Node 
data DocKey = KernelKey Int 
      | NodeKey Int 

docLookup :: DocKey -> Doc -> Maybe DocValue 

Lo bueno de esta solución es que sólo necesita una copia de cada una de las funciones API de mapa que usted necesita. Aquí hay una solución diferente que está más cerca del código que tienes.

newtype NodeKey = NodeKey Int 
newtype KernelKey = KernelKey Int 
lookupDocNode :: NodeKey -> Doc -> Maybe Node 
lookupDocKernel :: KernelKey -> Doc -> Maybe Kernel 

También podría hacer esta solución sin los nuevos tipos. Ambas soluciones le dan seguridad de tipo. En el primero, debe especificar lo que quiere con los tipos. En el segundo, lo especifica eligiendo a qué función llamar.

+0

No me gusta el tipo de clave unificada porque siempre sé cuando estoy obteniendo un tipo de otro. Tengo problemas con las funciones que combinan ambas teclas, se pueden confundir: por ejemplo: 'lookupNodeHasKernel :: Int -> Int -> Bool' – Zhen

Cuestiones relacionadas