:set rnu
). The current line number is zero, and the left-hand column shows the distance from your cursor. This way you can easily do commands like d5k
to delete the 5 lines above the cursor, or d5j
to delete the 5 lines below it.
A spillage of thought about Ubuntu, programming, economics, and computers in general.
:set rnu
). The current line number is zero, and the left-hand column shows the distance from your cursor. This way you can easily do commands like d5k
to delete the 5 lines above the cursor, or d5j
to delete the 5 lines below it.
// ...Good software techniques will tell you that you should break some of these up into methods:
// stuff 1
// ...
// stuff 2
// ...
// stuff 3
// ... etc.
If it gets big, you can even put it all in a collection and iterate (we're starting to get into weird coding now, I don't think anybody would actually do this):
stuff1();
stuff2();
stuff3();
var collection = new List<Action>() { stuff1, stuff2, stuff3 };Now the part where this would actually be useful. What if some of these functions could potentially be asynchronous? That is, they depend on some value that may not be readily available - maybe user input, maybe some data from a network, etc. Blocking is not usually a great option - a modal dialog demands that the user pays attention to it even if there is something more important somewhere else. It would be better if this computation could "pause" and then resume later on when we get what we need. In some languages including Scheme and Ruby, you can accomplish this using a construct called
foreach (var func in collection){
func();
}
callcc
:var collection = new List<Action<Action>>() { stuff1, stuff2,Here,
stuff3 };
foreach (var func in collection){
// pseudo-code warning
call_cc(func);
}
call_cc()
will call func
and pass in a function which will start executing right after the call_cc()
call: it is a continuation of the loop. When func
is done (or when it receives the response it wants), it can call this function to nicely continue executing the loop.callcc
. C# 5.0 will support the await
and async
keywords which will accomplish exactly what we want, but for the time being we'll have to make do with what we have. How can we do that without callcc
?void AsyncForeach(IEnumerator<Action<Action>> iter){This would require every function in
if (iter.MoveNext()){
iter.Current( () => {
AsyncForeach(iter);
});
}
}
void OtherFunc(){
// ...
var collection = new List<Action<Action>>() { stuff1, stuff2,
stuff3 };
AsyncForeach(collection.GetEnumerator());
}
collection
adhere to the Action<Action>
delegate and when it is done, it will need to call the continuation manually in order to resume the computation. This is a bit annoying, and it's why all the BeginConnect
, BeginSend
, etc. in System.Net
require an AsyncCallback
to call when they are done. The new async
and await
keywords will be extremely useful to accomplish our task since everything is called automatically:var collection = new List<Action>() { stuff1, stuff2, stuff3 };It is useful to learn this from approach though. Say we want to halt the loop prematurely from within one of the functions. In that case, the function could simply not call the continuation. That would end our recursion, causing us to break out of our loop - the equivalent of the
foreach (var func in collection){
// func doesn't even need to call anything to
// keep this thing going!
await func();
}
break
keyword. In order to do that with the await
keyword we'd have to have some sort of exception handling system, or return type, etc.for...else
construct where if break
is called somewhere in the computation it will run the else
block:for i in range(10):We can do this by adding failure "continuations" to our functions:
if i == 5:
break
else:
# this is executed
print "should run"
for i in range(10):
if i == 12:
break
else:
# this is not executed
print "should not run"
void AsyncForeach(IEnumerator<Action<Action, Action>> iter,In this case the functions
Action failure){
if (iter.MoveNext()){
iter.Current( () => {
AsyncForeach(iter, failure);
}, failure);
}
}
void OtherFunc(){
// ...
var collection =
new List<Action<Action, Action>>() { stuff1, stuff2, stuff3 };
AsyncForeach(collection.GetEnumerator(), () => {
// handle failure
});
}
stuff1
, stuff2
, etc. will call the first function if they should continue looping, or call the second one in case of failure.AsyncForeach
: it depends on the type of the list we're iterating over (IEnumerator<Action<Action, Action>>
), and it does not close over any variables that we may need for the loop. Can we do this using a closure?var collection =Since this isn't so DRY, we can top it all off with a function that returns a function:
new List<Action<Action, Action>>() { stuff1, stuff2, stuff3 };
// declare looper early so that it closes over itself
Action looper = null;
var iter = collection.GetEnumerator();
looper = () => {
if (iter.MoveNext()){
iter.Current(looper, () => {
// handle failure
});
}
};
// don't forget to start the loop
looper();
Action GetAsyncForeach<T>(IEnumerable<T> collection,We now have a DRY, re-usable component for implementing an asynchronous foreach loop in our code. It's not the most elegant approach, but it works really well and we don't need that much extra boiler plate to get this done (if C# supported a
Action<T> body){
var iter = collection.GetEnumerator();
return () => {
if (iter.MoveNext()){
body(iter.Current);
}
};
}
void OtherFunc(){
// ...
var collection =
new List<Action<Action, Action>>() { stuff1, stuff2, stuff3 };
Action checker = null;
checker = GetAsyncForeach(collection, (current) => {
current(checker, () => {
// handle failure
});
});
checker(); // start the loop
}
let rec
keyword, we could make it even shorter!).ShowDialog
would lock the entire GUI while the system waited for the user to input something, however sometimes the user would have to attend to something else before responding to the dialog. Since later actions in the loop depended on the result of the dialog box, a more asynchronous method was necessary.x = amb(1, 2, 3, 4)In this case
x
is all of 1, 2, 3, and 4. If you try to print out x
it will print out 1 because the act of printing it temporarily forces a value, but otherwise you can treat the variable as though it had all of those values.assert x.odd?In this case
x
would become just 1 and 3. If you then added a final assertion that x > 2
you would force a single value and x
would be 3. If you instead added the assertion x > 3
then x
would have no values: an exception would be thrown saying that x
is basically "impossible".a = amb(*1..10)This code would print out 3, 4, and 5 on the first output, followed by 6, 8, and 10 on the second. The
b = amb(*1..10)
c = amb(*1..10)
assert a**2 + b**2 == c**2
puts a, b, c
next_value
puts a, b, c
next_value
function would tell the amb
system to find another solution to the set of variables that satisfy the assertions we specified. If nothing else is found, an exception will be thrown.require 'rubygems'This is a pretty cool way to program, and it would be interesting to know when it might be practical to use. I tried it with a couple of problems on Project Euler but unfortunately since the backtracking method that
require 'amb'
include Amb::Operator
a = amb(*1..10)
b = amb(*1..10)
c = amb(*1..10)
# calling amb with no arguments causes it
# to backtrack until the criteria is met
amb unless a*a + b*b == c*c
# prints out the first match
puts "#{a}, #{b}, #{c}"
# prints out every match and then crashes
amb
puts "#{a}, #{b}, #{c}"
amb
uses isn't always the most efficient approach it would choke a bit. Perhaps if this gem gets some attention and some love, it might end up as something a bit more performant!