How does ArrowLoop work? Also, mfix?

妖精的绣舞 提交于 2019-11-29 21:23:18

In this code, they key piece is the delay 0 arrow in the rec block. To see how it works, it helps to think of values as varying over time and time as chopped into slices. I think of the slices as ‘days’. The rec block explains how each day's computation works. It's organised by value, rather than by causal order, but we can still track causality if we're careful. Crucially, we must make sure (without any help from the types) that each day's work relies on the past but not the future. The one-day delay 0 buys us time in that respect: it shifts its input signal one day later, taking care of the first day by giving the value 0. The delay's input signal is ‘tomorrow's next’.

rec     output <- returnA -< if reset then 0 else next
        next <- delay 0 -< output+1

So, looking at the arrows and their outputs, we're delivering today's output but tomorrow's next. Looking at the inputs, we're relying on today's reset and next values. It's clear that we can deliver those outputs from those inputs without time travel. The output is today's next number unless we reset to 0; tomorrow, the next number is the successor of today's output. Today's next value thus comes from yesterday, unless there was no yesterday, in which case it's 0.

At a lower level, this whole setup works because of Haskell's laziness. Haskell computes by a demand-driven strategy, so if there is a sequential order of tasks which respects causality, Haskell will find it. Here, the delay establishes such an order.

Be aware, though, that Haskell's type system gives you very little help in ensuring that such an order exists. You're free to use loops for utter nonsense! So your question is far from trivial. Each time you read or write such a program, you do need to think ‘how can this possibly work?’. You need to check that delay (or similar) is used appropriately to ensure that information is demanded only when it can be computed. Note that constructors, especially (:) can act like delays, too: it's not unusual to compute the tail of a list, apparently given the whole list (but being careful only to inspect the head). Unlike imperative programming, the lazy functional style allows you to organize your code around concepts other than the sequence of events, but it's a freedom that demands a more subtle awareness of time.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!