
apfelmus wrote:
Phlex wrote:
Donald Bruce Stewart wrote:
Yes and no. The point is that if you can't automate it, you have to code it by hand anyway which constitutes most of the hairiness. But I know what you mean and there's a nice way to do that with multi-parameter type classes.
Let's assume a data structure
data Universe = Universe [Galaxy] data Galaxy = Galaxy [Planet] data Planet = Planet { name :: String, size :: Double }
The insight is that in order to reference a planet inside the universe structure, you have to know the path from the top. In other words, you have to know that's it's the 2nd planet from the 4th galaxy before you look up its name. If you don't throw that information away, you can use it to update it as well. In effect, the Universe behaves like a finite map with composite keys.
{-# OPTIONS_GHC -fglasgow-exts -#} import Prelude hiding (lookup)
class Map map key a | map key -> a where lookup :: key -> map -> Maybe a adjust :: (a -> a) -> key -> map -> map
instance Map [a] Int a where lookup 0 [x] = Just x lookup 0 _ = Nothing lookup k (x:xs) = lookup (k-1) xs lookup _ _ = Nothing
adjust f 0 [x] = [f x] adjust _ 0 xs = error "Index out of range" adjust f k (x:xs) = x : adjust f (k-1) xs adjust f _ xs = error "Index out of range"
instance Map Universe Int Galaxy where lookup k (Universe gs) = lookup k gs adjust f k (Universe gs) = Universe (adjust f k gs)
instance Map Galaxy Int Planet where lookup k (Galaxy ps) = lookup k ps adjust f k (Galaxy ps) = Galaxy (adjust f k ps)
instance (Map m k m', Map m' k' a) => Map m (k,k') a where lookup (k,k') m = lookup k m >>= lookup k' adjust f (k,k') m = adjust (adjust f k') k m
You can lookup the 2nd planet in the 4th galaxy with
lookup (4,2) universe :: Maybe Planet
and you can update it via
adjust (\planet -> planet {name = "Earth"}) (4,2) universe
Thanks to type-classes and overloading, you can still access single galaxies with
lookup 4 universe :: Maybe Galaxy
Regards, apfelmus
This answers precisely my question. Hiding the access/update methods behind a common interface, that's the key ... Thanks a lot, Sacha