2016-05-03 15 views
1

Ich habe gerade begonnen, Erlang (und funktionale Programmierung) zu lernen, und ich bin auf einem einfachen Programm stecken. Das Ziel des Programms ist es, den größten Primfaktor einer Zahl zu finden. Das ist mein Programm:Debugging eines einfachen Programms in Erlang

lprime(N, L, D) when D == N-> 
    if N rem D == 0 -> D; 
     true-> L 
    end; 
lprime(N,L,D) -> 
    if N rem D == 0 -> 
     lprime(N/D, D, D); 
     true -> lprime(N, L, D+1) 
    end. 
lprime(N)-> 
    lprime(N,1,2). 

Hier ist, wie es für einige Eingaben ausgeführt werden soll:

lprime(3)->lprime(3,1,2)->lprime(3,1,3)->3 
lprime(36)->lprime(36,1,2)->lprime(18,2,2)->lprime(9,2,2)->lprime(9,2,3)->lprime(3,3,3)->3 
lprime(14)->lprime(14,1,2)->lprime(7,2,2)->lprime(7,2,3)->lprime(7,2,4)->lprime(7,2,5)->lprime(7,2,6)->lprime(7,1,7)->7 

Aber das Programm immer den ersten Primdivisor statt. lprime(24)->2, lprime(9)->3

ich ein äquivalentes schrieb (meiner Meinung nach) Programm in Python, die ich mehr vertraut bin mit, dass genau wie erwartet ausführt:

def lprime(N, L=1, D=2): 
    if D==N: 
     if N%D == 0: return D 
     return L 
    if N%D == 0: 
     return lprime(N/D, D, D) 
    return lprime(N, L, D+1) 

Ich habe auch versucht, eine andere Version ohne Schutz (es sieht auch cleaner) aber dieser in eine unendliche Rekursion zu gehen scheint, wieder der python-Äquivalent (IMO) wie erwartet funktioniert:

lprime2(1, L, D) -> 
    L; 
lprime2(N,L,D) -> 
    if N rem D == 0 -> 
     lprime2(N/D, D, D); 
     true -> lprime2(N, L, D+1) 
    end. 
lprime2(N)-> 
    lprime2(N,1,2). 

ich habe versucht, das Programm mit DBG zu debuggen, die Dokumentation von denen ist sehr spärlich und I don‘ verstehe die Schritte ver Gut. Die Schritte, die ich verwendet wurden, waren:

1> dbg:start(). 
{ok,<0.35.0>} 
2> dbg:tracer(). 
{ok,<0.35.0>} 
3> dbg:tp(first,lprime, 1, []). 
{ok,[{matched,[email protected],1}]} 
4> dbg:tp(first,lprime,3,[]). 
{ok,[{matched,[email protected],1}]} 
5> dbg:p(all,c). 
{ok,[{matched,[email protected],26}]} 
6> first:lprime(10). 
(<0.33.0>) call first:lprime(10) 
2 
7> first:lprime(10,1,2). 
(<0.33.0>) call first:lprime(10,1,2) 

Edit: Hervorhebungen
ich keine nützlichen Informationen aus diesem fand und ich schätzen würde keine Hinweise, wie man effektiv zu debuggen, aber vor allem würde ich möchte wissen, was das Programm zum Scheitern bringt.

+0

Mögliche Duplikate von [Using Trace und dbg in Erlang] (http://stackoverflow.com/questions/1954894/using-trace-and-dbg-in-erlang) –

+0

@SteveVinoski Verwendung von Trace und dbg ist meine zweitrangige Angelegenheit In erster Linie möchte ich wissen, warum dieses Programm fehlschlägt. –

+0

ein anderes Werkzeug ist die Debugger-Anwendung: debugger: start() – Pascal

Antwort

2

Sie verwenden Gleitkommadivision anstelle von Ganzzahldivision, und das verursacht Ausnahmen in rem. Aber Sie sehen diese Ausnahmen nicht, weil Sie rem in einem Wächter aufrufen.Sie können dies sehen von case mit eher als if:

lprime2(1, L, D) -> 
    L; 
lprime2(N,L,D) -> 
    case N rem D of 
     0 -> lprime2(N/D, D, D); 
     _ -> lprime2(N, L, D+1) 
    end. 
lprime2(N)-> 
    lprime2(N,1,2). 

So können Sie die Ausnahmen sehen:

1> c(lp). 
lp.erl:4: Warning: variable 'D' is unused 
{ok,lp} 
2> lp:lprime2(14). 
** exception error: an error occurred when evaluating an arithmetic expression 
    in function lp:lprime2/3 (/tmp/lp.erl, line 7) 

es zu beheben, verwenden div anstatt / in Ihrem zweiten Satz von lprime/3:

Im Allgemeinen verwendet idiomatischer Erlang-Code case mehr th ein if weil letzterer nur Wachen in seinen Klauseln erlaubt.

Eine andere Sache ist zu beachten, dass, wenn N == D, dann in Ihrem Code mit den Wachen auf dem Funktionsklauseln (wie auch in Ihrem Python-Code) N rem D immer wahr sein wird, so dass Sie den Code vereinfachen können:

lprime(N,_,N) -> 
    N; 
lprime(N,_,D) when N rem D == 0 -> 
    lprime(N div D, D, D); 
lprime(N,L,D) -> 
    lprime(N, L, D+1). 

im ersten Satz, verwenden wir die gleiche Variable N sowohl für die N und D Argumente. Diese Klausel wird nur ausgeführt, wenn N und gleich sind. In diesem Fall ist der Test rem nicht erforderlich.

+0

Danke. In praktisch jeder Sprache, die ich verwendet habe, wird '/' standardmäßig als Integer-Division verwendet, und Float muss umgewandelt werden. Und die Klärung des Falls ist sehr hilfreich. Ich habe 'Learn you old Erlang' als Referenz verwendet und es wurde speziell 'if' als 'was das if' eingeführt und jetzt weiß ich warum. –

1

Der Fehler bei der Portierung des Codes ist, dass in Python, 5/2 == 2 während in Erlang, 5/2 == 2.5. Sie müssen den div Operator verwenden: 5 div 2 == 2

1> 5/2. 
2.5 
2> 5 div 2. 
2 

Also, in Ihrem Code ersetzen:

lprime(N/D, D, D); 

mit:

lprime(N div D, D, D); 

Mit dieser Änderung ich die erwarteten Ergebnisse erhalten:

2> a:lprime(3). 
3 
3> a:lprime(36). 
3 
4> a:lprime(14). 
7 

Auf eine Randnotiz über Ihre Logik, ich bin mir ziemlich sicher, wenn N == D, N rem D wird immer gleich 0, so möchten Sie vielleicht den Code dort zu vereinfachen.

Verwandte Themen