Как индексировать тип «элемент» по значению «контейнер источника»?
Итак, у меня есть ситуация, очень похожая на этот (очень упрощенный) код:
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"
Как я могу использовать Haskell 'Система типов s (или расширения GHC) для ограниченияbefore
и аналогичные операции от взятияElement
с разныхContainer
s? Я'мы смотрели вGADTs
а такжеDataKinds
но, ну, этоЭто займет много времени, и я мог бы использовать некоторые предложения или указатели. (Еще одна идея, которую ямы думали, но еще нет: использовать такой же трюк, какST
монадыs
параметр ...)
Я слишком пессимистичен, если решу, что для этого потребуется язык с зависимой типизацией? Потому что, поскольку мое ограниченное понимание зависимой типизации идет, я думаю, что яя пытаюсь проиндексироватьElement
тип по значениямContainer
тип.
РЕДАКТИРОВАТЬ: Просто для дополнительного цвета, все это в конечном итоге возникает, потому что яЯ пытаюсь определить что-то очень похожее на это:
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
Весь этот код требует, чтобы вы никогда "микс» Element
с разныхContainer
s.