¿Cómo indexar un tipo de "elemento" por un valor de "contenedor de origen"?
Así que tengo una situación muy similar a este código (muy simplificado):
import Data.Maybe
import Data.List
data Container a = Container [a]
-- Assumption: an Element can only obtained from a Container. The operation
-- guarentees the Element is in the Container.
data Element a = Element (Container a) a
-- This operation is only valid for Elements that have the same Container.
before :: Eq a => Element a -> Element a -> Bool
before (Element (Container xs) x) (Element (Container ys) y)
| xs == ys = fromJust (elemIndex x xs) < fromJust (elemIndex y xs)
| otherwise = error "Elements from different Containers"
¿Cómo puedo usar el sistema de tipos de Haskell (o las extensiones de GHC) para restringirbefore
y operaciones similares de tomarElement
s de diferenteContainer
s? He estado investigandoGADTs
yDataKinds
pero, bueno, eso va a llevar mucho tiempo y podría usar algunas sugerencias o sugerencias. (Otra idea que he pensado, pero no he trabajado: usa un truco similar al deST
mónadas
parámetro...)
¿Soy demasiado pesimista si llego a la conclusión de que esto requeriría un lenguaje tipificado de manera dependiente? Porque, como mi comprensión limitada de la tipificación dependiente va, creo que estoy tratando de indexar elElement
tipo por valores de laContainer
tipo.
EDITAR: Solo para color adicional, todo esto surge en última instancia porque estoy tratando de definir algo muy parecido a esto:
import Data.Function
import Data.Ix
-- I want to use Elements as Array indexes; so Elements need to know
-- their Container to calculate their Int
instance Eq a => Ix (Element a) where
-- Ignore how crap this code is
range (l, u) = map (getSibling l) [getIndex l .. getIndex u]
index (l,u) i = index (getIndex l, getIndex u) (getIndex i)
inRange (l,u) i = inRange (getIndex l, getIndex u) (getIndex i)
getIndex :: Eq a => Element a -> Int
getIndex (Element (Container xs) x) = fromJust $ elemIndex x xs
getList :: Element a -> [a]
getList (Element (Container xs) _) = xs
getSibling :: Element a -> Int -> Element a
getSibling (Element (Container xs) _) i = Element (Container xs) (xs!!i)
instance Eq a => Eq (Element a) where
(==) = (==) `on` getIndex
instance Eq a => Ord (Element a) where
compare = compare `on` getIndex
Todo este código requiere que nunca se "mezcle"Element
s de diferenteContainer
s.