How does ArrowLoop work? Also, mfix? - haskell

I'm fairly comfortable now with the rest of the arrow machinery, but I don't get how loop works. It seems magical to me, and that's bad for my understanding. I also have trouble understanding mfix. When I look at a piece of code that uses rec in a proc or do block, I get confused. With regular monadic or arrow code, I can step through the computation and keep an operational picture of what's going on in my head. When I get to rec, I don't know what picture to keep! I get stuck, and I can't reason about such code.
The example I'm trying to grok is from Ross Paterson's paper on arrows, the one about circuits.
counter :: ArrowCircuit a => a Bool Int
counter = proc reset -> do
rec output <- returnA -< if reset then 0 else next
next <- delay 0 -< output+1
returnA -< output
I assume that if I understand this example, I'll be able to understand loop in general, and it'll go a great way towards understanding mfix. They feel essentially the same to me, but perhaps there is a subtlety I'm missing? Anyway, what I would really prize is an operational picture of such pieces of code, so I can step through them in my head like 'regular' code.
Edit: Thanks to Pigworker's answer, I have started thinking about rec and such as demands being fulfilled. Taking the counter example, the first line of the rec block demands a value called output. I imagine this operationally as creating a box, labelling it output, and asking the rec block to fill that box. In order to fill that box, we feed in a value to returnA, but that value itself demands another value, called next. In order to use this value, it must be demanded of another line in the rec block but it doesn't matter where in the rec block it is demanded, for now.
So we go to the next line, and we find the box labelled next, and we demand that another computation fill it. Now, this computation demands our first box! So we give it the box, but it has no value inside it, so if this computation demands the contents of output, we hit an infinite loop. Fortunately, delay takes the box, but produces a value without looking inside the box. This fills next, which then allows us to fill output. Now that output is filled, when the next input of this circuit is processed, the previous output box will have its value, ready to be demanded in order to produce the next next, and thus the next output.
How does that sound?

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.

Related

Time Complexity for index and drop of first item in Data.Sequence

I was recently working on an implementation of calculating moving average from a stream of input, using Data.Sequence. I figured I could get the whole operation to be O(n) by using a deque.
My first attempt was (in my opinion) a bit more straightforward to read, but not a true a deque. It looked like:
let newsequence = (|>) sequence n
...
let dropFrontTotal = fromIntegral (newtotal - index newsequence 0)
let newsequence' = drop 1 newsequence.
...
According to the hackage docs for Data.Sequence, index should take O(log(min(i,n-i))) while drop should also take O(log(min(i,n-i))).
Here's my question:
If I do drop 1 someSequence, doesn't this mean a time complexity of O(log(min(1, (length someSequence)))), which in this case means: O(log(1))?
If so, isn't O(log(1)) effectively constant?
I had the same question for index someSequence 0: shouldn't that operation end up being O(log(0))?
Ultimately, I had enough doubts about my understanding that I resorted to using Criterion to benchmark the two implementations to prove that the index/drop version is slower (and the amount it's slower by grows with the input). The informal results on my machine can be seen at the linked gist.
I still don't really understand how to calculate time complexity for these operations, though, and I would appreciate any clarification anyone can provide.
What you suggest looks correct to me.
As a minor caveat remember that these are amortized complexity bounds, so a single operation could require more than constant time, but a long chain of operations will only require a constant times the number of the chain.
If you use criterion to benchmark and "reset" the state at every computation, you might see non-constant time costs, because the "reset" is preventing the amortization. It really depends on how you perform the test. If you start from a sequence an perform a long chain of operations on that, it should be OK. If you repeat many times a single operation using the same operands, then it could be not OK.
Further, I guess bounds such as O(log(...)) should actually be read as O(log(1 + ...)) -- you can't realistically have O(log(1)) = O(0) or, worse O(log(0))= O(-inf) as a complexity bound.

Understanding Haskell's `map` - Stack or Heap?

Given the following function:
f :: [String]
f = map integerToWord [1..999999999]
integerToWord :: Integer -> String
Let's ignore the implementation. Here's a sample output:
ghci> integerToWord 123999
"onehundredtwentythreethousandandninehundredninetynine"
When I execute f, do all results, i.e. f(0) through f(999999999) get stored on the stack or heap?
Note - I'm assuming that Haskell has a stack and heap.
After running this function for ~1 minute, I don't see the RAM increasing from its original usage.
To be precise - when you "just execute" f it's not evaluated unless you use its result somehow. And when you do - it's stored according to how it's required to fulfill the caller requirements.
As of this example - it's not stored anywhere: the function is applied to every number, the result is output to your terminal and is discarded. So at a given moment in time you only allocate enough memory to store the current value and the result (which is an approximation, but for the case it's precise enough).
References:
https://wiki.haskell.org/Non-strict_semantics
https://wiki.haskell.org/Lazy_vs._non-strict
First: To split hairs, the following answer applies to GHC. A different Haskell compiler could plausibly implement things differently.
There is indeed a heap and a stack. Almost everything goes on the heap, and hardly anything goes on the stack.
Consider, for example, the expression
let x = foo 17 in ...
Let's assume that the optimiser doesn't transform this into something completely different. The call to foo doesn't appear on the stack at all; instead, we create a note on the heap saying that we need to do foo 17 at some point, and x becomes a pointer to this note.
So, to answer your question: when you call f, a note that says "we need to execute map integerToWord [1..999999999] someday" gets stored on the heap, and you get a pointer to that. What happens next depends on what you do with that result.
If, for example, you try to print the entire thing, then yes, the result of every call to f ends up on the heap. At any given moment, only a single call to f is on the stack.
Alternatively, if you just try to access the 8th element of the result, then a bunch of "call f 5 someday" notes end up on the heap, plus the result of f 8, plus a note for the rest of the list.
Incidentally, there's a package out there ("vacuum"?) which lets you print out the actual object graphs for what you're executing. You might find it interesting.
GHC programs use a stack and a heap... but it doesn't work at all like the eager language stack machines you're familiar with. Somebody else is gonna have to explain this, because I can't.
The other challenge in answering your question is that GHC uses the following two techniques:
Lazy evaluation
List fusion
Lazy evaluation in Haskell means that (as the default rule) expressions are only evaluated when their value is demanded, and even then they may only be partially evaluated—only far enough as needed to resolve a pattern match that requires the value. So we can't say what your map example does without knowing what is demanding its value.
List fusion is a set of rewrite rules built into GHC, that recognize a number of situations where the output of a "good" list producer is only ever consumed as the input of a "good" list consumer. In these cases, Haskell can fuse the producer and the consumer into an object-code loop without ever allocating list cells.
In your case:
[1..999999999] is a good producer
map is both a good consumer and a good producer
But you seem to be using ghci, which doesn't do fusion. You need to compile your program with -O for fusion to happen.
You haven't told us what would be consuming the output of the map. If it's a good consumer it will fuse with the map.
But there's a good chance that GHC would eliminate most or all of the list cell allocations if you compiled (with -O) a program that just prints the result of that code. In that case, the list would not exist as a data structure in memory at all—the compiler would generate object code that does something roughly equivalent to this:
for (int i = 1; i <= 999999999; i++) {
print(integerToWord(i));
}

Why are bacon.js observables classified lazy sequences?

My understanding of lazy sequences is that they don't load data in memory until it's accessed by the program. So I can see how this would make sense if there was a large list of numbers, waiting to be consumed, but the sequence only pulled in the data from the producer when the iterator called the next method.
But observables append the item to themselves whenever the producer pushes it to them. So it's not like the sequence loads the data when consumer asks for it, it loads it whenever the producer sends it. So in what way are observables lazy?
There are 2 kinds of laziness in Bacon.js Observables:
Observables don't register to their underlying data source (for example, an AJAX fetch) until there is at least one Observer. This laziness practically gives you automatic resource management in the sense that connections to data sources are automatically opened and closed based on demand. Also if there are multiple Observers, only a single connection to the data source is used and the results are shared.
Observables don't evaluate the functions passed to map, combine etc until the value is actually used. So if you do expensive calculation in the function you give to map and only sample the stream once in a second, only those values will be actually evaluated.
What you don't get is backpressure management. So if you're data source, say observable a, produces infinite values sequentially, you can either
process them immediately using a.onValue
take 1000 first of them using a.take(1000).onValue
take until some condition using a.takeUntil((x) -> x > 1000)).onValue
But you cannot affect the rate that the source produces the values, because Bacon.js provides no way to tell the source that "I'm interested in more values later, I'll tell you when". I've been thinking about adding something like this, but it would complicate matters a lot.
As the bottom line, I'd say that Bacon.js is not your ideal library for working with infinite lists, for instance, in the Haskell style. And AFAIK, neither is any other Javascript FRP lib.
A lazy sequence is a sequence that evaluates its elements at the last time possible. What's useful about them is that you can pass the sequence around and even perform operations on it without evaluating its contents.
Since you don't evaluate the sequence, you can even create an infinite sequence; just make sure that you don't evaluate the whole of it. For example, the following Haskell program creates an infinite sequence of natural numbers, then lazily multiplies each element by 2, producing an infinite sequence of even numbers, then takes the first 5 elements, evaluating them (and only them):
take 5 (map (*2) [1..])
-- [2,4,6,8,10]
Basically, with lazy sequences and a set of functions that work over them, like map, you can write programs that create and process potentially infinite streams of data in a composable way.
Which, incidentally, is exactly what (functional) reactive programming is about. An observable can be seen as a potentially infinite stream of pairs (value, timestamp). An operation on an observable, such as map, simply creates another stream based on the original one. Attaching a consumer to an observable evaluates the elements of it that "already happened", while leaving the rest un-evaluated.
For example, Bacon's observable.map can be implemented as a function that lazily applies a function to the 'value' part of the stream (again in Haskell):
map f = Prelude.map (\(value, tstamp) -> (f value, tstamp))
while observable.delay adds delay to the 'timestamp' part:
delay dt = Prelude.map (\(value, tstamp) -> (value, tstamp + dt))
where Prelude.map is just a regular "map" function over lazy sequences.
Hopefully I haven't confused you any further!

Optimally iterating in Haskell with termination conditions and differing iteration steps

I am trying to write a simple iterating algorithm in Haskell, but I'm struggling to find the optimal solution in terms of elegance and speed.
I have an algorithm that needs to apply an operation to a state over a number of iterations until some stopping condition is reached, recording the state using some arbitrary function. I already know how to implement a scheme like this by defining a function like iterateM.
But in this case the operation to perform for each step depends on the state, and boils down to checking a 'step type' condition to decide on the next iteration types, and then performing operation A for the next 10 iterations, or performing operation B for the next iteration before checking the condition again.
I could write it in an imperative style as:
c=0
while True:
if c>0:
x=iterateByA(x)
c=c-1
else:
if stepCondition(x)==0:
x=iterateByA(x)
c=9
else:
x=iterateByB(x)
observeState(x)
if stopCondition(x):
break
and of course this could just be copied in Haskell, but I would rather do something more elegant.
My idea is to have the iteration use a list of functions to pop and apply to the state, and update that list with a new one (based on the 'step type' condition) once it is empty. I'm slightly concerned that this will be inefficient though. Would doing this and using something like
take 10 (repeat iterateByA)
compile away all of the list allocation etc to a tight loop that only uses a counter, like the imperative one above?
Is there another neat and efficient way of doing this?
If it helps this is for an adaptive stochastic simulation algorithm, the iteration steps update the state and the step condition (that decides the best simulation scheme) is a function of the current state. There are infact 3 different iteration schemes but I figured that an example with 2 is easier to explain.
(I'm not sure if it matters but I should probably also point out that in haskell the iterateByX functions are monadic since they use random numbers.)
A direct translation doesn't look too bad.
loop c x
| stopCondition x = observe x
| c > 0 = observe x >> iterateByA x >>= loop (c-1)
| stepCondition x = observe x >> iterateByA x >>= loop 9
| otherwise = observe x >> iterateByB x >>= loop c
The repetition of observe can be removed via various tricks if you don't like it.
You should probably rethink things, though. This is a very imperative approach; probably something much better can be done (but it's hard to say how from the few details you've given here).

Behavior in reactive-banana

Pardon me, I'm just starting to look into reactive-banana and FRP.
The author of reactive-banana made this example per my suggestion, in which he creates a counter which can be increased and decreased. He uses accumE function which accumulates events. I think I was able to somewhat grok the Event type, and was able to test quite a few things with it, but then I remembered that there was also Behavior. I looked into it, but it seems like the behavior is meant to be used in similar situations; to modify an existing variable, just like accumE does with events.
What does Behavior mean, and what are the use cases for it?
I agree with Ankur rather than Chris: a text box is a value over time and so naturally wants to be a behavior rather than an event. The reasons Chris give for the less natural choice of event are implementation issues and so (if accurate) an unfortunate artifact of the reactive-banana implementation. I'd much rather see the implementation improved than the paradigm used unnaturally.
Besides the semantic fit, it's pragmatically very useful to choose Behavior over Event. You can then, for instance, use the Applicative operations (e.g., liftA2) to combine the time-varying text box value with other time-varying values (behaviors).
Semantically, you have
Behavior a = Time -> a
That is, a Behavior a is a value of type a that varies over time. In general, you know nothing at all about when a Behavior a would change, so it turns out to be a rather poor choice for updating a text field on the click of a button. That said, it would be easy to get a behavior that expresses the current value of the number in the counter example. Just use stepper on the event stream, or alternatively, build it from scratch the same way, except by using accumB instead of accumE.
Typically, things you hook up to input and output will always be Events, so Behavior is used internally for intermediate results.
Suppose that in the given example, you want to add a new button that remembers the current value, like the memory function on simple calculators. You would start out by adding a memory button and a text field for the remembered value:
bmem <- button f [text := "Remember"]
memory <- staticText f []
You need to be able to ask for the current value at any time, so in your network, you'd add a behavior to represent it.
let currentVal = stepper 0 counter
Then you can hook up events, and use apply to read the value of the behavior every time the Remember button is pressed, and produce an Event with that sequence of values.
emem <- event0 bmem command
let memoryE = apply (const <$> currentVal) emem
And finally, hook up this new event to the output
sink memory [text :== ("", show <$> memoryE)]
If you wanted to use memory internally, then again you'd want a Behavior for its current value too... but since we only ever use it to connect it to an output, we only need an event for now.
Does that help?
Library author speaking. :-)
Apparently, Chris Smith can read minds because he accurately describes what I am thinking. :-)
But Conal and Arthur have a point, too. Conceptually, the counter is a value that varies in time, not a sequence of event occurrences. Thus, thinking of it as a Behavior would be more appropriate.
Unfortunately, behaviors do not come with any information about when they will change, the are "poll-only". Now, I could try to implement various clever schemes that will minimize the polling and thus allow effient updates of GUI elements. (Conal does something similar in the original paper.) But I have adopted a "no magic" philosophy: the library user shall be responsible for managing updates via events himself.
The solution I currently envision is to provide a third type besides Event and Behavior, namely Reactive (name subject to change) which embodies qualities of both: conceptually, it's a value that varies in time, but it also comes with an event that notifies of changes. One possible implementation would be
type Reactive a = (a,Event a)
changes :: Reactive a -> Event a
changes (_, e) = e
value :: Reactive a -> Behavior a
value (x, e) = stepper x e
It is no surprise that this is precisely the type that sink expects. This will be included in a future version of the reactive-banana library.
EDIT: I have released reactive-banana version 0.4 which includes the new type, which is now called Discrete.
Generally, Behavior is a value that changes over a period of time. It is a continuous value, where as events are discrete values. In case of Behavior a value is always present.
For example: The text on a text box is a Behavior as the text can change over a period of time but there will be a current value, where as a keyboard stroke in a event as you cannot query a keyboard stroke for its "current" value.

Resources