306 karma · joined September 1, 2014
Stack Overflow: http://stackoverflow.com/users/1091208/amnn
Github: https://github.com/amnn
But on top of that, there is another issue with this representation: Your interpreter will very likely be dog slow, because you have to make a function call on each iteration, and it cannot be inlined, because it is dynamic.
And I suspect there are implications for the I-Cache that should probably be considered as well.
EDIT By "considered", I mean, measured, and then considered.
You, for example, probably very quickly realised that if you wanted to make games with a GUI, QBASIC was not the tool for you, but by the sounds of it, that didn't dissuade you.
Personally, I'm of the opinion that your very first language doesn't matter very much. As a programmer, you will (should) be learning plenty more, so the first one is more about learning how to learn than anything else.
The docs say that if you don't give a branch factor, a sensible choice is made for you, probably to get nodes to fit neatly into cache lines, so seeing as we are storing 35 unsigned 64 bit integers, this would be around 16 or 32 elements in a single node, and a depth of about 2. This means that, because the current implementation of BTreeMap does linear searches at insertion, for this particular use case, the BTreeMap isn't doing much better than a plain old array, that you are insertion sorting.
TL;DR: Storing the results in a vector and then in-placing sorting it could be faster, but not noticeably. I know this isn't the point of the article, but it was just an observation I had :)
[1]: https://doc.rust-lang.org/std/collections/struct.BTreeMap.ht...
Now I know that you can hide unsafePerformIO in the interface, and in this case I expect it is fine, but this is not easy, it feels like a hack.
Another example that I have personally watched play itself out in disbelief was in a fairly large Haskell project: There was need of a lookup table, with some 10000 elements. In such cases, I would have stored the lookup in a database, or a separate file at least, but because they wanted to maintain purity so badly, the solution was to write a 10000 line long Haskell file. But wouldn't it be nice if you could load a file and tell Haskell: don't worry, this won't change, so treat reads to this purely.
I never said such things were impossible, merely not easy, and I don't believe this is by accident. I am almost certain that such things are made difficult to prevent abusing such features, but that doesn't stop me from missing them :) .
What I do miss though (dearly) is that there is a certain cost as to what can be encapsulated. For instance, in Haskell, it is no longer so easy to hide side effects behind a pure interface.
It goes from Deterministic Finite Automata (equivalent in power to regular expressions in their purest sense, as opposed to POSIX regexps) to Context-Free Grammars and then finally Turing Machines. So this will give an idea of the hierarchy that TMs sit in.
Also, there are plenty of variations of Turing Machines with lots of cool properties. If you want to have a look, try searching for "Non-Deterministic Turing Machines", "Probabilistic Turing Machines", or "Alternating Turing Machines".
I found these structures cropping up alongside Horn clauses, and Context-Free Grammars in interesting ways. In this case, viewing make rules as Horn clauses allows us to use a variant of Horn-SAT to find the minimum set of files we have to produce to build a rule, which is interesting to think about, and reason about.
This article felt as though it was food for thought and not really trying to push any particular idea too hard. In any case, I found it interesting as it found parallels to the sorts of structures I found when exploring various algorithms for Context-Free Grammars (such as pruning, or detecting erasable non-terminals, which can both be described in terms of Horn-SAT).
Sometimes, if you want an example to be both small and instructive, you'll have to put up with some contrivances.
Too often I see people conflating "X is good" for "X is good for everything" when that is so rarely, if ever, true.
But what about if we define entropy in terms of something like parts of speech? Then, the computer can only change one part of speech (the noun phrase to which we compare a summer's day) whilst maintaining the context of the sentence, so in terms of that metric, entropy is low.
With this parts of speech entropy metric in hand maybe we could declare the output of a computer to be "written by a computer" if the entropy in its sentences approaches that of a human writing about the same topic.
Disclaimer: I spent about as much time thinking about this as you did just reading it, so I don't expect this is in any way a fully formed or implementable idea, just food for thought.
One advantage of compiling to something like an SKI or BCKW basis (or a mix) is that you can represent abstraction (functions/closures) without bound variables, or scoping, which can be a pain to implement (esp. in hardware).
Take, for example, the SKI basis. Suppose you had two functions, with types as follows:
f :: a -> b
g :: b -> a -> c
And you wished to combine them in the natural way to get `h`: h :: b -> c
h x = g (f x) x
Then, to achieve the same with S, K and I combinators we do the following (assuming we have SKI representations of `f, g` as `F, G`. H := S(S(KG)F)I
The `x` has disappeared! But, if we apply H to some CL expression `X` we get: HX = S(S(KG)F)IX
= S(KG)FX(IX) ;; apply S
= KGX(FX)(IX) ;; apply S
= G(FX)(IX) ;; apply K
= G(FX)X ;; apply I
We can use S to Split (duplicate) parameters, and K to Kill (ignore) parameters, in a very straight forward way. Imagine the AST of the original code: App
/\
/ \
App x
/\
/ App
g /\
/ \
f x
Every `App` is replaced with an `S`, every `x` with an `I`, everything else (`y`) is replaced with `Ky`. In my example, I have also gone to the trouble of "optimising" `S(KF)I` away, as it is equivalent to just `F`.Interesting stuff, and plenty of theoretical grounding to boot. Especially as this sort of thing has started enjoying a renaissance, in the likes of "point-free" notation in languages like Haskell.
[1]: http://en.wikipedia.org/wiki/SECD_machine [2]: http://en.wikipedia.org/wiki/SKI_combinator_calculus [3]: http://en.wikipedia.org/wiki/B,C,K,W_system [Turner79]: http://courses.cecs.anu.edu.au/courses/COMP3610/assignments/... (apologies, I couldn't seem to find a version with an intact abstract).
In fact, taking the geometric mean of the man month values (which, I think, but am not sure is the right metric to use when comparing ratios), we find the average ratio to be 0.947x. Make of this what you will, given the size of the sample.
[1]: http://research.microsoft.com/en-us/groups/ese/nagappan_tdd....