[Haskell-cafe] Avoiding Dependency loops
martin
martin.drautzburg at web.de
Sun Oct 25 11:29:46 UTC 2015
Am 10/25/2015 um 12:03 PM schrieb David Turner:
> Hi Martin,
>
> Tempted to agree with you that Process has no business knowing about its runner - even in OO-land this would seem a bit
> unexpected to me. On the other hand, if PrcRunner is a function that takes a Process as its second argument, does a
> Process's prcRunner field ever run a Process other than the one that owns it? If not, it strikes me that partially
> applying it on construction be better: data PrcRunner = PrcRun (Timed Event -> State System EventQu)?
This was where I was caught in OO-land. You are absolutely right and your answer helps a lot.
> Or you could
> decide to keep your types mutually recursive and define them all in their own .Types module and then your various
> implementation modules can depend on that without introducing any cycles.
>
> Basically, there's lots of options depending on what you're trying to do! Drawing the boundaries around modules is
> definitely an art and not a science - there's a good (albeit OO-centric) article
> http://martinfowler.com/articles/refactoring-dependencies.html where Fowler says/"The hardest part of splitting a
> program into modules is just deciding on what the module boundaries should be. There's no easy guidelines to follow for
> this, indeed a major theme of my life's work is to try and understand what good module boundaries will look
> like." /which you may find interesting.
>
> Cheers,
>
>
> On 25 October 2015 at 10:35, martin <martin.drautzburg at web.de <mailto:martin.drautzburg at web.de>> wrote:
>
> Thanks David.
>
> Maybe I better show the actual code;
>
> * module Process *
>
> data Process r = Prc {
> prcSources :: [Port],
> prcSinks :: [Port],
> prcRunner :: r,
> prcId :: PrcId
> } deriving (Show)
>
>
> * module System *
>
> data System = Sys {
> sysProcesses :: ProcessDb,
> sysItems :: ItemDb
> } deriving Show
>
> type ProcessDb = M.Map Int (Process PrcRunner)
>
> data PrcRunner = PrcRun (Timed Event -> Process PrcRunner -> State System EventQu)
>
>
> I understand your reasoning about the type contraints, but I cannot see what I should actually do.
>
> AS for your second suggestion of splitting things up even more, I don't think this will help, because the loop is
> already on type level.
>
> My feeling is that I got caught in OO thinking too much and the runner should not be part of the process at all. But
> again I cannot see how to fix it. The thing is, Process itself does not really have any business with its Runner. There
> is no function which actually does anyting with it. The Process type just provides a home for the runner.
>
> Thinking aloud:
>
> On top of the whole thing sits a simulation, which among others changes the state of the System. This includes changes
> to the Processes. I want to capture this by altering the Runner associated with a particular Process. Wouldn't this
> suggest that System needs an association between Process and Runner rather than making Runner a field of Process?
>
>
> Am 10/25/2015 um 10:01 AM schrieb David Turner:
> > Hi Martin,
> >
> > Seems reasonable to me. It's a common dependency-breaking technique, akin to introducing an interface in OO-land. Did
> > you also introduce a typeclass constraint on the type 'r' so you can call some methods on it too? If not then Process
> > doesn't really depend on System at all.
> >
> > Another thing to look for is that perhaps your System module splits into two bits, one low-level (defining types and so
> > on) and one high-level (making use of everything in System and Process and Runner) and the two bits live at opposite
> > ends of the dependency graph. I've found that quite a common situation to be in when splitting things up into modules too.
> >
> > HTH,
> >
> > David
> >
> >
> >
> >
> > On 25 October 2015 at 08:36, martin <martin.drautzburg at web.de <mailto:martin.drautzburg at web.de> <mailto:martin.drautzburg at web.de
> <mailto:martin.drautzburg at web.de>>> wrote:
> >
> > Hello all,
> >
> > I just split up a program I'm working on into several source files and ran into the following difficulty:
> >
> > module Process implements Process which has a field Runner. Runner is a basically a function which alters a 'System'
> > state. So Process needs Runner, Runner needs System and thus Process needs System.
> >
> > module System implements among others a collection of Processes (because Processes can alter their states). So System
> > needs Process.
> >
> > Eh voila, I have a loop.
> >
> > What I did was to leave the type of the Runner unspecified in Process, i.e. I now have (Process r) where r is the type
> > of the Runner. Thus Process no longer needs to know about System.
> >
> > This does work, but it feels strange and I'm a bit worried that this is an indication for a design flaw, but I cannot
> > see it.
> > _______________________________________________
> > Haskell-Cafe mailing list
> > Haskell-Cafe at haskell.org <mailto:Haskell-Cafe at haskell.org> <mailto:Haskell-Cafe at haskell.org
> <mailto:Haskell-Cafe at haskell.org>>
> > http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
> >
> >
>
>
More information about the Haskell-Cafe
mailing list