[plt-scheme] Was HTDP 21.1.2 - Why I "don't" use the design recipe, etc.

From: Stephen Bloch (sbloch at adelphi.edu)
Date: Thu Jul 13 12:44:28 EDT 2006

At 10:31 AM +0100 7/13/06, wooks . wrote:
>If someone were to write the 10 commandments of professional 
>software development 3 of them would be
>Thou shalt not rely on comments in the code
>Thou shalt only use  comments where the code requires clarification
>There is no silver bullet development technique - Development 
>standards are guidelines not mantras that must be slavishly followed.
>The design recipe says otherwise. It insists that I comment every 
>function I write even if like sum, length or factorial it would 
>appear that such comments are superfluous from the perspective of 
>clarification. From what I have seen  as far as I have progressed so 
>far (chap 21 of HTDP) and as is being reinforced to me the intent is 
>that the mantras are slavishly followed.

Let me point out a couple of things.

1) The design recipe in HtDP is written for beginning programmers. 
We require beginning programmers to follow the recipe strictly and 
slavishly in order to instill habits.  (If you allow them to make 
their own exceptions too early, they'll just ignore the design recipe 
altogether.)  Once those habits are instilled and the student has 
developed some mature programmer judgment, one can be more flexible. 
Indeed, I don't always follow all the steps of the design recipe in 
my own programming... but when I get in trouble, and the program 
starts to resemble the LaBrea tar pits, I start over with more 
explicit attention to contracts, writing test cases first, etc.  It 
serves to clear my mind so I can resolve these fundamental issues 
without worrying about code at the same time.  And it serves the same 
purpose for my beginning students.

2) I assume that by "comment every function" you mean writing 
function contracts?  PLT Scheme actually allows you to write function 
contracts IN the language, not in comments, so they can be enforced 
by the language.  I don't teach that in a first-term course, because 
it's more syntax to learn, and comment syntax is trivial.  In 
particular, one of the attractions of the HtDP design recipe for 
beginning students is that the first step is non-intimidating -- you 
won't get a syntax error from a contract comment.  Anyway, since 
you're experienced enough not to be intimidated by the syntax, open 
the Help Desk and look up contract.ss.

Incidentally, I had a boss (when I was out in semi-private industry) 
who actively opposed comments, saying "A comment is something that 
the human reader can see and the computer can't, and hence a source 
of misunderstanding between them."  For that matter, my first-term 
college CS prof, who usually required extensive commenting, gave us 
one assignment on which we were forbidden to use any comments except 
our names, to give us practice writing readable code without relying 
on comments.  There's a lot to be said for your first two 
commandments.  (The third too, but that's a separate topic.)

>>... plus, map  returns a [Listof Y], while fold returns a Y.  So 
>>how could we hope  to implement map in terms of fold, as you say?
>Maybe I should ask the question that struck me immediately I saw 
>this problem. Why would I want to do this anyway. Map and fold are 
>clearly intuitive one is a translation the other is a summarisation. 
>I cannot intuitively see why I would want to implement a translation 
>in terms of a summarisation.

Perhaps because you were in an environment that provided one and not 
the other?  That kind of thing certainly happens in the real world.

Of course, the real, pedagogical reason for the problem is to expand 
the reader's conception of higher-order functions and their 
applicability.  To point out that "fold" CAN be usefully used with S 
and T being different types -- exactly the lesson you're trying to 

>>Once again, the X's and Y's in the contract for fold are 
>>independent  from the X's and Y's for map, and we could instantiate 
>>it ...
>>The names don't matter at all; in fact, we could instead use the 
>>names S and T:
>>;; fold : forall S, T . T (S T -> T) [Listof S] -> T
>I would more readily accept this with an example of a case where we 
>summarised 2 different types of data - but lets see.

Well, "map" is a good example, but that's what you're having trouble 
with already.  Let's try a more prosaic example: use "fold" to write 
a "highest-salary" function on a list of employees.  The input is a 
list of employees, so S must be "employee"; the output is a number, 
so T must be "number".

>Hmmm well all the instantation and matching stuff  looks a lot like 
>prolog - but no its not crystal clear because the reason why I would 
>want to do this is not intuitive.

Bingo!  Given the contracts

>>;; map :  (X -> Y) [Listof X] -> [Listof Y]
>>;; fold : T (S T -> T) [Listof S] -> T

we need to unify (in the Prolog sense) the inputs [Listof X] and 
[Listof S], which is easy, and we need to unify the outputs [Listof 
Y] with T.  There's a unique solution to these unifications, and it 
tells you a lot about how to solve the problem.

>>(Hint: go back write the instantiation of fold for sum, product, 
>>_and_ append.  Look at the resulting classes of data.)
>For sum S and product
>    S is a number and T is a list of numbers.

Why is T a list of numbers?  Last I checked, sum and product each 
returned a number.

>For append S is a list  so I suppose T is a list of list?

Why is T a list of lists?  append returns a list.

I'm being a little overly simplistic here, insisting that the return 
value from the function must unify with T; in practice, you could do 
a "fold" and then do something else to the result.  But let's start 
with the simpler approach in which map (or highest-salary or sum or 
product or append) IS merely a call to fold with carefully chosen 
arguments; if that doesn't work, we can make things more complicated 

					Stephen Bloch
					sbloch at adelphi.edu

Posted on the users mailing list.