Overzicht en programmeerstijl

Intro

Om overzicht te houden in programmeerproject (met name de groteren), heeft men programmeerstijlen uitgevonden. Die zijn vergelijkbaar met schrijfstijlen (informeel, formeel(brief), formeel(artikel) en wat dies meer zei.

Het nut van dergelijke stijlen is vooral consistentie; je doet altijd alles op dezelfde manier. Bij programmeerstijlen zijn er ook nog praktische aspecten: de ene stijl ligt meer voor de hand als de andere met een bepaalde taal.

stijlen

Besproken (of liever aangestipte) stijlen (N.B. de beschrijvingen hieronder zijn analogie/schets, geen feiten):
De een is niet beter of slechter dan de ander, alhoewel de een misschien wel beter bij jou of het probleem waaraan je werkt past, als de ander. In de praktijk vind je vooral mengvormen.

functies, procedures, en return values

Functies zijn stukjes onafhankelijke code die een bepaalde specifieke taak uitvoeren. Bij het ontwerpen van zo'n functie heb je keuzes: hoeveel en welke parameters krijgt deze functie, maar ook welke return-values. Nu, een functie ZONDER return values wordt meestal 'procedure' genoemd. Een procedure is dus feitelijk een speciaal soort functie. Pascal bijvoorbeeld doet alleen maar procedures (omwille van de systematiek), als ik het wel heb. Lisp doet alleen maar functies, i.e. het heeft altijd een return-value, of je hem nu gebruikt of niet. Het kiezen voor functies danwel procedures is voornamelijk een stijlkwestie aangezien je ook om het gebrek aan return-value van procedures heen kunt programmeren, bijv. middels globale variabelen.

Het NIET gebruiken van return-values als ze er toch zijn, is daarentegen meer een gebrek aan stijl :) Vergelijk de volgende stukjes pseudo-code:

1) y = (square x) OF (set! y (square x))
2) (square x y)
Optie 1 is, met gebruikmaking van de return-value van de functie 'square', onmiddelijk duidelijk. Optie 2, in Scheme context, lijkt eerder vatbaar voor de interpretatie "kwadrateer x, en ook y", als je het mij vraagt. Maar 'y' kan natuurlijk ook de variabele zijn waar je het resultaat in stopt.

andere stijlzaken

Ondertussen zijn we er allemaal achter dat je in Scheme liever niet dingen als 'x = x + 1' doet. Dit is een eigenaardigheidje van Scheme in het bijzonder en declaratief programmeren in het algemeen.

Maar hoe doe je dan een loopje als:

x=1;
while (x < 10) x = x + 1;
in Scheme?

(define t1 (lambda (x) x))
(define test (lambda (i max)
	(cond 
		((or  (not (number? max)) (equal? max 0)) "No max")
		((not (number? i))  "No iterator")
		((> i max) "Done") ;**
		(else (begin
			(display "i=")
			(display i)
			(display " result=")
			(display (t1 i))    ;***
			(newline)
			(test (+ i 1) max) ;*
		       )
		)
	)
))

Ik heb hier dus niet 1 keer een toekenning/assignment gepleegd op 'i' ... Ik hoog 'i' (impliciet) precies 1 keer op (per aanroep) bij *.

Voor mijn triviale 't1' functie kun je natuurlijk iedere willekeurige functie gebruiken, incl. return-values. Let ook op de laatste regel output (hier "Done") dat de return-value is van 'test' zelf. Typisch komt de return-value van een functie ter beschikking van de aanroepende functie (zie ***). Als je die functie zelf met de hand hebt aangeroepen, komt-ie op het scherm (zie **).

'Test' is hier een zogenaamde wrapper-functie, die voor de programmeur 't1' aanroept met de juiste argumenten, zo vaak als nodig. Deze 'truuk', een functie om je basis functie heen schrijven die het lastige werk voor je doet, is bij tijd en wijle erg handig :)

Opdracht

Analyseer je eindopdracht (indien al bekend, anders je tussenopdracht) in termen van probleemstelling, opdelen van probleem in deelproblemen (die uiteraard corresponderen met aanwezige functies :), etc, zodat je
  1. overzicht hebt in je programma, en
  2. begrijpt en kunt uitleggen welke functies er zijn, en waarom.