[plt-scheme] Was HTDP 21.1.2 - Why I "don't" use the design recipe
>From: Felix Klock's PLT scheme proxy <pltscheme at pnkfx.org>
>To: "wooks ." <wookiz at hotmail.com>
>CC: plt-scheme at list.cs.brown.edu
>Subject: Re: [plt-scheme] HTDP 21.1.2
>Date: Tue, 11 Jul 2006 09:26:19 -0400
>
>Wooks-
>
>On Jul 11, 2006, at 8:58 AM, wooks . wrote:
>
>>fold is a reducing function - produces a consolidated value from multiple
>>inputs (eg list).
>>
>>map is a one to one function.
>>
>>So there is a mismatch at contract level (hence why methinksh trick
>>question) .
>
>Its a _tricky_ question, not a trick question.
>
>Richard's suggestion was sound; you haven't shown us the circles you drew
>according to his instructions, so we can't critique your work there, and
>must assume that you made a mistake in the execution of his suggestion.
>
>But, since you brought up contracts, lets look at the contracts for map
>and fold, and see if that leads us down a different path for the solution.
>
>;; map : (X -> Y) [Listof X] -> [Listof Y]
>
>;; fold : hmm, you didn't give a contract for fold in the code you posted
>earlier. Shame on you for still failing to follow the design recipe; at
>some point people are going to stop responding.
>
I am extremely appreciative of all the help I have gotten here but I wish to
say something that I think applies generally to people of my background.
In my first job as a trainee programmer in 1983 I was sent on a cobol
programming course. About 2 years after this I joined a local government
institution as a sort of "advanced trainee" and received further instruction
in JSP.
For the benefit of anybody reading who thinks JSP stands for Java Server
Pages,
JSP (Jackson Structured Programming) is a data structure based approach to
program design. You diagrammize your input data structures according to some
very simple conventions then you merge the data structure diagrams into a
program structure. Next you list instructions needed to process the data and
then allocate those instructions at the appropriate places on the structure
diagram diagram. Finally you mechanically translate (again according to
another simple convention) from the diagram, first to psuedocode and then to
your target programming language. The diagrams and other design materials
are retained as your program documentation. If you need to amend the program
you work from the structure diagrams and list from the documentation you
produced not the code- you amended structure diagrams and/or the list of
operations or change the way they were allocated to the structure diagram
and then implemented the corresponding changes to the code.
I had no trouble adjusting I guess because back then I was still in my
programming diapers and I remeber being very receptive to it . Nonetheless
when I graduated from the training department and was placed in one of the
project teams I pretty soon learnt that the "real programmers" regarded that
stuff as mumbo jumbo and didn't work that way. I remember there being a need
to amend a program that my team had originally outsourced to the Training
Department. It had come back with all the JSP parephanalia and used
program inversion (a technique for resolving clashes between the input data
structures in your program) for it's print routine. Program inversion
results in impenetrable code (at least in COBOL) so you are wholly dependent
on the structure diagrams for its maintenance - I had been in the team long
enough to forget how to apply the technique and was young enough to succumb
to the peer pressure of viewing it as mumbo jumbo so the program had to be
sent back to the Training Dept for amendment because "real programmers"
couldn't amend it from the code and wouldn't read the program design
documentation that came with it.
Needless to say that is not a situation a Project Team Leader would want to
be in - so do you think he changed the programming "standards" to conform
with J what the Training Dept did. Not a chance - rather it was the training
school graduates who had to do the adjusting. So it was in every other
project team and everywhere else I went - with one exception 6 years later.
I worked at a place that used a JSP development package - Microfocus Cobol
Workbench. To the best of my knowledge the product has since been withdrawn
from the marketplace and the fact that the acronym JSP has now been usurped
for something Java related probably suggests that industries did not persist
with its affinity for the methodology.
Although I haven't taken much persuading to adopt the design recipe I have
yet to conceptualise how this approach to training programmers prepares them
for maintenance work.
I don't know what the statistics are today but a substantial part of a
professional programmers job is maintenance of code that has not been
written or maintained using a data structure oriented or any other
systematic approach. A project manager may take a look at an HTDPed
candidate and rightly wonder how useful this person is going to be for all
the maintenance work his department need to do and the thought that a person
might try to implement design reciped induced rewrites to all the code he's
given to maintain will probably send a shiver up his/her spine.
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.
OK - well as it happens I'm sold on it and since my university programming
curriculum (I am now a mature student) always sets greenfield development
project problems (as opposed to maintenance) I get an instant return. BUT
I've come from an environment where if you went to a colleague for help he
would expect you to show him code, not comments hence it is still my
instinct to troubleshoot from code. Yes I have learnt (or should I say
relearnt) that troubleshooting from the contracts and data structure
documentation is extremely effective but it will take time for me to flip
the neuron in my brain that says don't rely on comments in code. So it is
with some of the other aspects of design recipe that contradict the habits
of the professional programmer - I look back on some of the solutions to
problems I have had and realise that my background programs me to not to
consider solutions that seem to point towards repetitive computations.
When I posted the code requesting help for this problem it never occured to
me to post the contract even (though I did write one) simply because
AFAIwasC my code was just the equivalent of an if else statement. I did not
see that supporting it with comments was clarifying anything - the code was
as much clarification as anybody would need. I have not yet re-acclimated to
the habit of using design documentation as my primary debugging weapon. I
instinctively think of them as comments and 2nd class citizens in the
debugging stakes.
Thinking back to when I was being taught JSP the only challenge it presented
to my then programming mindset was that program inversion required you to
use lots of GOTOs in your COBOL code - but I was persuaded that the
resulting code was just a mechanised translation of a structured technique.
In fact it was just a higher level of programming - you were not meant to
work from the COBOL you produced (just like you don't work from machine
code) but from the design documentation.
These days there are alot more neurons to flip. Sometimes my instincts are
right - do you think I wrote blue-eyed-ancestor in chapter 14 - hell no - I
wrote X-eyed-ancestor and parameterised the colour - in chapter 20 I found
baby steps codified as design recipe for doing what I had instinctively
done.
So please, it is not a case of rejecting the design recipe when things don't
appear to be all there. Some of these things are instinct others require
some serious cranial neuron flipping. Yes I still waste far too much time
dry running code instead of looking more closely at my design documentation.
Alas thats the way you have to work to deal with amending code in the "real
world" (that phrase that programmers use to justify bad habits) so for
people like me it is a habit changing experience. When you are customising
an insurance package for a client or amending a telephone companys billing
system they are habits that you need.
>But since I want to actually put content in this post, and since you could
>find this information from Figure 57, I'll fill in the blank, using the
>argument order you gave in your post.
>
>;; fold : X (X Y -> Y) [Listof X] -> Y
>
>Now, if you look at these two contracts, they certainly look very
>different. map takes two arguments, fold takes three; 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.
>The mistake in the reasoning in the preceding paragraph is the assumption
>that the X's and Y's in the contract for map have anything to do with the
>X's and Y's in the contract for fold. Each pair of parameters is
>independent, implicitly quantified in each contract. If we wanted to be
>really formal about it, we could have written our contracts like so:
>
>;; map : forall X,Y . (X -> Y) [Listof X] -> [Listof Y]
>
>What this is saying is that X and Y are contract parameters that, at each
>invocation of map, you can replace with different classes of data. Thus,
>we can plug in X:=Num, Y:=String to get:
>
>;; map : (Num -> String) [Listof Num] -> [Listof String]
>
>This is often called "instantiation" or "speciailizaton" of the contract;
>we're taking our (very general) contract and deriving a more specific one
>for our particular needs at one point in the program.
>
>Likewise,
>
>;; fold : forall X, Y . Y (X Y -> Y) [Listof X] -> Y
>
Well I had a more conservative
;; fold : X (X X -> X) (listof X) -> X
>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 like so: X:=Num
>Y:=Num to yield
>
>;; fold : Num (Num Num -> Num) [Listof Num] -> Num
>
>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.
>
>This makes it crystal clear that the parameters for fold are totally
>different from the ones for map.
>
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.
>Now my question for you, wooks, is this:
>
>We have:
>
>;; map : (X -> Y) [Listof X] -> [Listof Y]
>;; fold : T (S T -> T) [Listof S] -> T
>
>So, what class of data could you plug in for the contract parameter T to
>make fold return the same class of data as map?
T would have to be a list.
>When you do this plugging in, what is the resulting instantiated contract
>for fold?
;fold : list (S list of S -> list of S)
> How should S be instantiated?
>
>(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.
For append S is a list so I suppose T is a list of list?
I still don't understand how any of this helps me produce a list of the
squares of a list of numbers.