[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