[Haskell-cafe] I just don't get it (data structures and OO)

Phlex Phlex at telenet.be
Sun Jun 3 07:48:00 EDT 2007



Tillmann Rendel wrote:
> Hello,
>
> Phlex wrote:
>> changePlanetAge universe galaxy planet age = ...lots of code, 
>> returning a new universe
>> And the same code for all functions updating any of the properties of 
>> my planet ...
>> And the same code for all functions updating properties of a country 
>> on this planet...
>
> In functional programming, problems of the kind "and the same code for 
> all functions doing something related" are most often solved by 
> introducing higher order functions. Let's try to decompose the problem 
> as follows:
>
> (1) change an attribute
> (2) change a planet by changing one of it's attributes
> (3) change a galaxy by changing one of it's planets
> (4) change an universe by changing one of it's galaxies.
>
> (1) is done by functions of type (Attribute -> Attribute). We will 
> construct them on the fly.
>
> For (2), we need functions for each attribute of a planet.
>
>   type Name = String
>   type Age = Integer
>   data Planet = Planet Name Age
>
>   -- lift name changer to planet changer
>   changeName :: (Name -> Name) -> Planet -> Planet
>   changeName f (Planet n a) = Planet (f n) a
>
>   -- lift age changer to planet changer
>   changeAge :: (Age -> Age) -> Planet -> Planet
>   changeAge f (Planet n a) = Planet n (f a)
>
> we need one of these functions for each attribute of each object. they 
> correspond to setter-Methods in oop.
>
> For (3), we have to select one of the planets in a galaxy to be 
> changed. Let's assume integer indices for all planets.
>
>   type Galaxy = [Planet]
>
>   -- lift planet changer to galaxy changer
>   changePlanet :: Integer -> (Planet -> Planet) -> Galaxy -> Galaxy
>   changePlanet 0 f (p:ps) = f p : ps
>   changePlanet n f (p:ps) = p : changePlanet (pred n) f ps
>
> For (4), we have to select one of the galaxies in a universe to be 
> changed. Let's assume integer indices again.
>
>   type Universe = [Galaxy]
>
>   -- lift galaxy changer to universe changer
>   changeGalaxy :: Integer -> (Galaxy -> Galaxy) -> Universe -> Universe
>   changeGalaxy 0 f (g:gs) = f g : gs
>   changeGalaxy n f (g:gs) = g : changeGalaxy (pred n) f gs
>
> Oups, that's the same as (3), up to renaming of types and variables. 
> Let's refactor it to
>
>   -- lift element changer to list changer
>   changeElement :: Integer -> (a -> a) -> [a] -> [a]
>   changeElement f 0 (x:xs) = f x : xs
>   changeElement f n (x:xs) = x : changeListElement f (pred n) xs
>
>   -- provide nicer names
>   changePlanet = changeElement
>   changeGalaxy = changeElement
>
> Let's see how we can use this:
>
> To set the name of the second planet of the third galaxy to "earth":
>
>   (changeGalaxy 2 $ changePlanet 1 $ changeName $ const "earth") univ
>
> To increase the age of the same planet by 1:
>
>   (changeGalaxy 2 $ changePlanet 1 $ changeAge $ succ) univ
>
> Using map instead of changeElement, we can change all galaxies or 
> planets at once:
>
>   --  provide nicer names
>   changeGalaxies = map
>   changePlanets = map
>
> To set the name of the first planet in all galaxies to "first":
>
>   (changeGalaxies $ changePlanet 0 $ changeName $ const "first") univ
>
> To increase the age of all planets by one:
>
>   (changeGalaxies $ changePlanets $ changeAge $ succ) univ
>
> A possible next step is to use typeclasses as supposed by apfelmus to 
> access elements of different structures in a uniform way.
>
>   Tillmann
>

This is very informative, and easier to grasp for such a newbie as me.
So the idea is to take the "changing function" down the chain, i knew 
this couldn't be that hard !
Still this requires indeed to think different, I guess i'm up for quite 
a few exercises in order to wrap my mind around this.

That's the kind of information that's missing from all these tutorials i 
found around the web.

Thank you,
Sacha


More information about the Haskell-Cafe mailing list