[prev in list] [next in list] [prev in thread] [next in thread] 

List:       haskell-cafe
Subject:    Re: [Haskell-cafe] Avoiding Dependency loops
From:       martin <martin.drautzburg () web ! de>
Date:       2015-10-25 11:29:46
Message-ID: 562CBD2A.7060908 () web ! de
[Download RAW message or body]

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@web.de \
> <mailto:martin.drautzburg@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@web.de \
> > <mailto:martin.drautzburg@web.de> <mailto:martin.drautzburg@web.de
> <mailto:martin.drautzburg@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@haskell.org <mailto:Haskell-Cafe@haskell.org> \
> > <mailto:Haskell-Cafe@haskell.org
> <mailto:Haskell-Cafe@haskell.org>>
> > http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
> > 
> > 
> 
> 

_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic