
How to design co-programs - matt_d
https://patternsinfp.wordpress.com/2018/11/21/how-to-design-co-programs/
======
smadge
The intermediate representation of the binary tree for QuickSort in this
article was a “eureka” moment for me. I think algorithm and data structure
curriculums should take this approach.

~~~
pwm
Completely agree. Maybe it’s because CS curricula tends to teach
searching/sorting algorithms before data structures, specifically BSTs. Not
sure why...

If you think about it a BST defines order and a sorting algorithm achieves it
so naturally the output of a sort can be seen as a BST (flattening it to a
list is somewhat irrelevant).

~~~
tom_mellior
> Maybe it’s because CS curricula tends to teach searching/sorting algorithms
> before data structures, specifically BSTs.

I think it's more because sorting is all about "efficiency", and sorting
things without allocating a ton of intermediate data structures is viewed as
more efficient. The blog does mention the deforestation optimization, which
(if implemented sufficiently heroically) would remove the intermediate tree in
the QuickSort example. But now we're straying pretty far from a simple sorting
algorithm in a first high-level algorithms course to a more complex and less
abstract beast that is only maximally efficient if you assume a heroic
compiler.

As a side note, heap sort
([https://en.wikipedia.org/wiki/Heapsort](https://en.wikipedia.org/wiki/Heapsort))
_does_ perform sorting by constructing an intermediate heap data structure.
It's just that the data structure is implicit as it is built in-place in the
array to be sorted.

> If you think about it a BST defines order and a sorting algorithm achieves
> it so naturally the output of a sort can be seen as a BST (flattening it to
> a list is somewhat irrelevant).

Or, similarly, the construction of a BST _is_ a sort:
[https://en.wikipedia.org/wiki/Tree_sort](https://en.wikipedia.org/wiki/Tree_sort)

~~~
smadge
> I think it's more because sorting is all about "efficiency", and sorting
> things without allocating a ton of intermediate data structures is viewed as
> more efficient.

I agree that probably explains a lot of it.

However the cost to efficiency is not that large and may be worth the gains in
conceptual clarity. First, the traditional implementation of QuickSort has an
implicit (or virtual?) intermediate data structure, the function call tree.
Second, I have limited understanding of lazy evaluation, but in a lazy
language I believe ‘flatten’ would begin consuming the tree as it is still
being built by ‘build’.

~~~
tom_mellior
> First, the traditional implementation of QuickSort has an implicit (or
> virtual?) intermediate data structure, the function call tree.

That's a good point, but function calls have a constant cost in terms of stack
frame allocation and deallocation.

> Second, I have limited understanding of lazy evaluation, but in a lazy
> language I believe ‘flatten’ would begin consuming the tree as it is still
> being built by ‘build’.

Yes, that is correct. The entire tree is not allocated at once, only the nodes
that are actually needed, as well as dynamic data representing suspended
computations of the rest of the data structure. But (again, ignoring compiler
optimizations that would make them go away) these are allocations on the
garbage-collected heap and thus incur GC costs and complexity.

Overall I agree that there would be value in illustrating algorithms by also
showing the version that constructs the computation tree. But I don't think it
should be _the one_ presentation of the algorithm, only a device to further
understanding of the "real" implementation.

~~~
smadge
Yes, definitely. For example, the explanation of MergeSort in CLRS’s
“Introduction to Algorithms” has a figure which shows tree a of lists being
transformed into another shorter tree of lists where the lower nodes have been
merged.

------
bmc7505
A Mathematical Theory of Codesign:
[https://arxiv.org/pdf/1512.08055.pdf](https://arxiv.org/pdf/1512.08055.pdf)

------
emmanueloga_
Funny how the author gave this talk in honor of Felleisen's on his 60th
birthday. "Hi, to honor you I'll talk about how one of your better known works
is incomplete and only shows half of the picture".

I started reading HTDP long ago but at the time I made the huge mistake of
taking a detour to learn Racket, and later Scheme... HTDP provides small
languages just to save students from the herculean effort of having to learn a
whole programming language and environment. Way to miss the point.

Anyway, there's some associated documentation on the Racket site about a
library called "2htdp/universe" [1]. The architecture described is very close
to the so called "ELM architecture" [2] or even Redux [3]. Probably (maybe?)
there's no relation though, since coming to this architecture appears to be
really natural when working with functional programming languages.

1: [https://docs.racket-
lang.org/teachpack/2htdpuniverse.html#%2...](https://docs.racket-
lang.org/teachpack/2htdpuniverse.html#%28part._world._interactive%29)

2: [https://guide.elm-lang.org/architecture/](https://guide.elm-
lang.org/architecture/)

3: [https://redux.js.org/](https://redux.js.org/)

~~~
geezerjay
> "Hi, to honor you I'll talk about how one of your better known works is
> incomplete and only shows half of the picture".

...or, you know, that old "standing on the shoulders of giants" thing.

~~~
guest2143
Newton's "..standing on the shoulders of giants..." was a dig at Hook (who was
short). It's Isaac being an arrogant jerk, which he was in spades. (Even if he
revolutionized thinking in a number of areas.) It's not a statement of
humbleness..

~~~
geezerjay
> Newton's "..standing on the shoulders of giants..." was a dig at Hook

The quote precedes Newton by half a millennia.

[https://en.wikipedia.org/wiki/Standing_on_the_shoulders_of_g...](https://en.wikipedia.org/wiki/Standing_on_the_shoulders_of_giants)

------
atopos
Nice article!

Something along these lines is still present, I think, in HtDP, at least in
the Chapter about abstractions (16.1, 16.5, and 16.6).

Basically, when designing a function one can use existing abstractions (or, I
would add, design her own abstraction) whose whole signature, output included,
matches the purpose and signature of the function to be designed.

So, if the problem at hand is to design a function that takes a natural number
and produces a list, that calls for using the built-in `build-list`, whose
signature is `N [N -> X] -> [List-of X]`. Or if the output of a function on
lists is a Boolean value, one has to keep an eye on `ormap`/`andmap`, etc. So
the output is also essential to choose the suitable abstraction.

~~~
nuclx
This reminds me of type-driven programming as in Idris using the Type-Define-
Refine workflow as described by Brady.

