2013-01-11 13 views
5

Folgen < Real World Haskell >, es heißt foldl' sind strenge Version von foldl.Was bedeutet strict version in haskell?

Aber es ist schwer für mich zu verstehen, was bedeutet strict ??

foldl f z0 xs0 = lgo z0 xs0 
     where 
      lgo z []  = z 
      lgo z (x:xs) = lgo (f z x) xs 


foldl' f z0 xs0 = lgo z0 xs0 
    where lgo z []  = z 
      lgo z (x:xs) = let z' = f z x in z' `seq` lgo z' xs 
+2

Vergleichen Sie den Quellcode für die beiden Versionen von Foldl, und Sie könnten aufgeklärt werden. – augustss

+0

@augustss vielleicht, können Sie das beantworten? – jackalope

+0

Wie Sie sehen können, berechnet foldl 'das erste Argument für lgo vor dem Aufruf, während foldl (im Allgemeinen) ein Thunk übergibt, das bei Bedarf ausgewertet wird. – augustss

Antwort

6

faltl und (der strenge) faltl 'sind semantisch gleichwertig. Der Unterschied liegt in der Leistung, besonders wenn Sie eine große Liste durchqueren. Die Faulheit hat einen Overhead des Aufbaus eines Thunk und Foldl 'ist der effizientere Weg, um zu diesem Ergebnis zu kommen, weil es keinen riesigen Thunk baut.

Es ist ein wirklich guter Artikel zu erklären dies im Detail auf Haskell Wiki

Strengen Funktionen funktioniert wie Funktionen in C oder anderen Sprachen, dass ihre Argumente im Allgemeinen mit Spannung ausgewertet werden.

0

Eine strikte Funktion ist eine Funktion, deren Argumente vor dem Körper ausgewertet werden.

+0

immer noch schwer zu verstehen ... – jackalope

+1

Nein, es ist keine Funktion, deren Argumente vor dem Aufruf ausgewertet werden. Eine strikte Funktion ist informell eine Funktion, die ihre Argumente auswertet. – augustss

+0

@augustss: * unbedingt (richtig?) –

12

Es ist nicht allgemein bekannt, aber foldl' ist tatsächlich nicht-strikt in seinem Akku-Argument! Rufen Sie den Typ:

foldl' :: (a -> b -> a) -> a -> [b] -> a 

Seine Strenge in Argument 2 ist abhängig von der Strenge der Funktion für Argument 1, wie Sie sehen, wenn Sie const passieren:

Prelude Data.List> foldl' (const (+1)) undefined [1] 
2 
Prelude Data.List> foldl' (const (+1)) undefined [1..4] 
5 

Sie hätte gedacht, naiv, dass "foldl" streng ist, bedeutet "streng im Akkumulatorargument". Das Obige widerspricht dem.

Allerdings ist es noch heimtückischer, da die Strenge nur auf das Ergebnis der Funktionsanwendung im Cons-Fall der Schleife zurückzuführen ist. So erhalten Sie noch Böden, wenn Sie den Basisfall eintreten, aber nicht die induktive Fall:

Prelude Data.List> foldl' (const (+1)) undefined [] 
*** Exception: Prelude.undefined 

so die Strikt in argument 2auch hängt von der Wert Argumentations 3!

So würde ich es schreiben: "voll" streng in seinem 2. Argument.

foldl' f z0 xs0 = go z0 xs0 
    where 
    go !z []  = z 
    go !z (x:xs) = go (f z x) xs 

, die in ihrem zweiten Argument wirklich streng, wie man sehen kann:

Prelude Data.List.Stream> foldl' (\a b -> 1) undefined [undefined] 
*** Exception: Prelude.undefined 

mit der Version Haskell2010 Vergleich:

Prelude Data.List.Stream> Data.List.foldl' (\a b -> 1) undefined [undefined] 
1 

Diese actuall eine praktische Wirkung hat - die Die aktuelle Definition wird ihr Akkumulatorargument nicht konsequent auspacken.

Historischer Hinweis: Dies wurde entdeckt, als wir die Striktheitssemantik der Listenbibliothek für das Stream Fusion Paper im Jahr 2007 spezifizierten, und der Ansatz zur Spezifizierung der Strenge ist in Duncan Coutts PhD thesis angegeben.