<div dir="ltr">Hi Martin,<div><br></div><div>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)? 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.</div><div><br></div><div>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 <a href="http://martinfowler.com/articles/refactoring-dependencies.html">http://martinfowler.com/articles/refactoring-dependencies.html</a> where Fowler says<i> "<span style="color:rgb(48,54,51);font-family:OpenSans,sans-serif;line-height:22.4px">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." </span></i>which you may find interesting.</div><div><span style="font-size:12.8px"><br></span></div><div><span style="font-size:12.8px">Cheers,</span></div><div><span style="font-size:12.8px"><br></span></div></div><div class="gmail_extra"><br><div class="gmail_quote">On 25 October 2015 at 10:35, martin <span dir="ltr"><<a href="mailto:martin.drautzburg@web.de" target="_blank">martin.drautzburg@web.de</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Thanks David.<br>
<br>
Maybe I better show the actual code;<br>
<br>
* module Process *<br>
<br>
data Process r = Prc {<br>
            prcSources  :: [Port],<br>
            prcSinks    :: [Port],<br>
            prcRunner   :: r,<br>
            prcId       :: PrcId<br>
} deriving (Show)<br>
<br>
<br>
* module System *<br>
<br>
data System = Sys {<br>
            sysProcesses :: ProcessDb,<br>
            sysItems     :: ItemDb<br>
} deriving Show<br>
<br>
type ProcessDb = M.Map Int (Process PrcRunner)<br>
<br>
data PrcRunner = PrcRun (Timed Event -> Process PrcRunner -> State System EventQu)<br>
<br>
<br>
I understand your reasoning about the type contraints, but I cannot see what I should actually do.<br>
<br>
AS for your second suggestion of splitting things up even more, I don't think this will help, because the loop is<br>
already on type level.<br>
<br>
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<br>
again I cannot see how to fix it. The thing is, Process itself does not really have any business with its Runner. There<br>
is no function which actually does anyting with it. The Process type just provides a home for the runner.<br>
<br>
Thinking aloud:<br>
<br>
On top of the whole thing sits a simulation, which among others changes the state of the System. This includes changes<br>
to the Processes. I want to capture this by altering the Runner associated with a particular Process. Wouldn't this<br>
suggest that System needs an association between Process and Runner rather than making Runner a field of Process?<br>
<span class=""><br>
<br>
Am 10/25/2015 um 10:01 AM schrieb David Turner:<br>
> Hi Martin,<br>
><br>
> Seems reasonable to me. It's a common dependency-breaking technique, akin to introducing an interface in OO-land. Did<br>
> you also introduce a typeclass constraint on the type 'r' so you can call some methods on it too? If not then Process<br>
> doesn't really depend on System at all.<br>
><br>
> Another thing to look for is that perhaps your System module splits into two bits, one low-level (defining types and so<br>
> on) and one high-level (making use of everything in System and Process and Runner) and the two bits live at opposite<br>
> ends of the dependency graph. I've found that quite a common situation to be in when splitting things up into modules too.<br>
><br>
> HTH,<br>
><br>
> David<br>
><br>
><br>
><br>
><br>
</span><span class="">> On 25 October 2015 at 08:36, martin <<a href="mailto:martin.drautzburg@web.de">martin.drautzburg@web.de</a> <mailto:<a href="mailto:martin.drautzburg@web.de">martin.drautzburg@web.de</a>>> wrote:<br>
><br>
>     Hello all,<br>
><br>
>     I just split up a program I'm working on into several source files and ran into the following difficulty:<br>
><br>
>     module Process implements Process which has a field Runner. Runner is a basically a function which alters a 'System'<br>
>     state. So Process needs Runner, Runner needs System and thus Process needs System.<br>
><br>
>     module System implements among others a collection of Processes (because Processes can alter their states). So System<br>
>     needs Process.<br>
><br>
>     Eh voila, I have a loop.<br>
><br>
>     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<br>
>     of the Runner. Thus Process no longer needs to know about System.<br>
><br>
>     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<br>
>     see it.<br>
>     _______________________________________________<br>
>     Haskell-Cafe mailing list<br>
</span>>     <a href="mailto:Haskell-Cafe@haskell.org">Haskell-Cafe@haskell.org</a> <mailto:<a href="mailto:Haskell-Cafe@haskell.org">Haskell-Cafe@haskell.org</a>><br>
>     <a href="http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe" rel="noreferrer" target="_blank">http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe</a><br>
><br>
><br>
<br>
</blockquote></div><br></div>