2010-07-08 4 views
8

I haben folgende Funktion definiert:Warum bewertet diese Haskell-Anweisung nicht träge?

ex 1 x = 1 
ex 0 x = 0 
ex b x = b ** x 

Dann, wenn ich folgendes auszuführen:

1 `ex` (sum [1..]) 

es versucht, die Summe der unendlichen Folge zu berechnen, anstelle von faul und 1 zurückkehrt. Warum?


EDIT: Bei der weiteren Untersuchung fand ich, dass Faulheit passiert, wenn ich die ex Funktion in einer Datei definieren, aber nicht, wenn ich es in GHCI definieren:

$ ghci 
GHCi, version 6.8.2: http://www.haskell.org/ghc/ :? for help 
Loading package base ... linking ... done. 
Prelude> let ex 1 x = 1 
Prelude> let ex b x = b ** x 
Prelude> ex 1 (sum [1..]) 
<interactive>: out of memory (requested 1048576 bytes) 

Wenn ich die ex Definition ziehen in eine Datei (in diesem Fall test.hs):

$ ghci 
GHCi, version 6.8.2: http://www.haskell.org/ghc/ :? for help 
Loading package base ... linking ... done. 
Prelude> :load test.hs 
[1 of 1] Compiling Main    (test.hs, interpreted) 
Ok, modules loaded: Main. 
*Main> ex 1 (sum [1..]) 
1.0 

Die neue Frage ist also, warum?

+1

Nein, 1 'ex' (Summe [1 ..]) gibt 1.0 auf meinem Computer zurück. Welche version von ghc etc.? Und erhalten Sie mit ex 1 (Summe [1 ..]) dasselbe Ergebnis? – ShreevatsaR

+1

Möglicherweise ein Fehler? –

+0

@ShreevatsaR: Gute Punkte, siehe mein Update oben. – perimosocordiae

Antwort

17

In GHCi ist, jede let Anweisung führt eine neue Definition von ex, anstelle von mehreren Musterfällen wie Sie es erwarten. Es hängt also, weil, wenn Sie danach ex 1 (sum [1..]) eingeben, nur die letzte ex b x = b ** x Version existiert.

Wenn Sie eine Funktion mit mehreren Musterfällen in GHCi definieren wollen, müssen Sie es in einer einzigen let Erklärung setzen, wie folgt aus:

let ex 1 x = 1; ex 0 x = 0; ex b x = b ** x 

Gleiches gilt für irgend etwas anderes, die normalerweise über mehrere Zeilen geschrieben werden, z. B. do Notation. Zum Beispiel kann eine Funktion wie folgt aus:

f x = do 
    y <- get 
    put (x + y) 
    return y 

möchte diese in GHCi geschrieben werden müssen:

let f x = do { y <- get; put (x + y); return y } 
+0

Aha, das ist wirklich unbequem. Gut zu wissen, aber danke! – perimosocordiae

+6

@perimosocordiae: Als ziemlich starker Benutzer von GHCi habe ich mir angewöhnt, die meisten oder alle meiner Definitionen in eine externe Datei zu schreiben, die Datei mit GHCi zu laden und die REPL hauptsächlich zur Auswertung einfacher Ausdrücke zu verwenden. –

+2

Sie können auch ': set + m' verwenden, um Definitionen über mehrere Zeilen zu schreiben. – aleator

-2

Ich habe einen Punkt der Faulheit verpasst, was die Antwort unten falsch macht.


sum Da die Gesamtsumme aller Elemente in der Sequenz berechnet. Was in Ihrem Fall endlos ist.

Sie wahrscheinlich

map ((curry ex) 1) [1..] 

möchten, dass

map -- map each item x to y 
    (
     (
      curry ex -- curry ex, to transform (x, y) -> z into x -> y -> z 
     ) 
     1 -- then invoke it with 1, which results in y -> z, x being 1 
    ) 
    [1..] -- the infinite sequence to be mapped. 
+0

Hm, ich glaube nicht, dass es das ist. Siehe mein Update oben. – perimosocordiae

+0

Verdammte Updates. Ja, ganz offensichtlich, was das Problem ist. – Dykam

+0

-1: Es würde nur die Summe auswerten, wenn es tatsächlich benötigt würde, und in diesem Fall war es nicht. – Zifre

1
Prelude> let ex 1 x = 1 
Prelude> let ex b x = b ** x 

Sie eine Funktion mit zwei Fälle hier nicht definieren. Sie definieren eine Funktion mit einem Fall und definieren sie dann erneut, indem Sie die vorherige Definition überschreiben.

Um eine Funktion mit zwei Mustern zu definieren, verwenden Sie let ex 1 x = 1; ex b x = b ** x, d. H. Trennen Sie die Fälle mit einem Semikolon.