Inleiding Programmeren + R

Debug

» Start

Debug


Wat doen we als een zo juist door ons gemaakte functie niet [goed] blijkt te werken? We hebben klaarblijkelijk bij intypen van de programmacode een fout gemaakt. Of misschien een logische fout, als de functie wel werkt maar er komt een verkeerd antwoord uit. We vragen ons vertwijfeld af wat voor fout het is, en in welke regel van de functie hij precies is gemaakt.


Stel dat de functie gewoon niet goed werkt. Hij stopt voor dat ie een antwoord geeft, en er verschijnt een foutboodschap op het scherm.  We kunnen verschillende strategiĆ«n volgen om de fouten op te sporen. 

De eerste vraag waarmee we zitten is de volgende: is het een toevalllige fout, of is de fout makkelijk weer op te roepen? Van toevallige fouten, die zo maar lijken te gebeuren zonder regelmaat of patroon, is het heel lastig om de oorzaak op te sporen.  Je bent al een stuk dichter bij de oplossing als je de fout herhaaldelijk weet op te roepen. 


Neem het volgende voorbeeld. We willen met behulp van een functie de variatiecoefficient berekenen van een variabele door de standaarddeviatie te delen door het gemiddelde. Wat blijkt? Als de waarden van de variable armlengte positief zijn werkt de functie naar behoren, maar zodra armlengte nul is gaat het fout :


    > vacov <- function(x) {

    +       sd(x / mean(x))

    +       }

    > armlengte <- 0

    > cv(armlengte)

    Error in var(x, na.rm = na.rm) : missing observations in cov/cor


In de foutboodschap wordt gesproken over de functie var(), die we echter helemaal niet gebruiken in onze functie vacov. Om uit te vinden waar de aanroep van var() vandaan komt gebruiken we de functie traceback().


    > traceback()

    3: var(x, na.rm = na.rm)

    2: sd(x / mean(x))

    1: cv(armlengte)


Dit lijstje met stappen laat zien dat var() wordt aangeroepen door de functie sd, en dat vervolgens in var() een fout (missing observations) optreedt. Onze berekening x / mean(x) moet die missing observation hebben veroorzaakt.

Het regel voor regel uitvoeren van de code kan nu helpen. Dus net doen of de programma-regels samen een script vormen, en die regels stuk voor stuk knippen/plakken achter de prompt en kijken of ze werken. Bij een eenvoudige functie zoals sd in dit voorbeeld is dat een goede benadering. 


    > mean(armlengte)

    [1] 0

    > armlengte / mean(armlengte)

    [1] NaN


Aha! We kunnen wel het gemiddelde uitrekenen van het getal 0, maar nul delen door nul geeft een missing value. De functie sd werkt dus alleen met een invoer die uit positieve getallen bestaat. We kunnen vervolgens onze functie aanpassen aan deze bevinding:


    > vacov <- function(x) {

    +       stopifnot(all(x>0))

    +       sd(x / mean(x))

    +       }

    > armlengte <- 0

    > cv(armlengte)

    Error: all(x>0) is not TRUE


Zit de functie ingewikkelder in elkaar, bijvoorbeeld met [veel] voorwaardelijke opdrachten en lussen, en je wilt toch regel voor regel controleren wat er gebeurt en of er wat gebeurt, dan kun je dat doen door gebruik te maken van de functie debug. De naam van de functie waar je de fout uit wilt halen [wilt debuggen] moet je als argument meegeven bij de aanroep van debug(), bijvoorbeeld zo:


    > debug(mijn_programma)  # zet de debugger aan om mijn_programma te volgen

    > mijn_programme(input)  # start mijn_programma met reguliere input

    Browse[1]>             # de debugger staat te wachten bij regel 1 van mijn_programma


Pas door een Enter te geven wordt de volgende stap van mijn_programma uitgevoerd. Na iedere stap kun je nu controleren wat de waarden zijn van de variabelen die je er van verdenkt je programma ergens te laten crashen.