2013-07-22 17 views
5

Dies ist eine Referenzfrage dazu: StackOverflow in continuation monad
mit denen ich ein wenig spielte und ein paar Erläuterungen benötigen würde.Wie funktioniert das Delay genau in continuation monad um Stackoverflow zu verhindern?

1) Ich nehme an, dies:

member this.Delay(mk) = fun c -> mk() c 

das Verhalten in Computational Workflow macht den diffrence tun, wie durch toyvo zwischen diesen zeigte:

cBind (map xs) (fun xs -> cReturn (f x :: xs)) 

cBind (fun c -> map xs c) (fun xs -> cReturn (f x :: xs)) 

So kann ich nicht genau verstehen, was die Trick, wenn
(fun c -> map xs c) nur unterschiedliche Schreibweisen von (map xs)

2) Infer ist Problem. - In OPs zweitem Map-Beispiel habe ich herausgefunden, dass es aufgrund eines Inferenzproblems mit dem v Wert nicht kompiliert wird, weil es f als a -> b list statt a -> b ergibt. Warum leitet es auf diese Weise? In Fall let v = f x würde es gut schließen.

3) Es scheint mir, dass VS ungenaue Art Signaturen in dem Tooltips zeigt: Rückgabetyp der Rückkehr der Monade ist: ('e->'f)->f, während der Rückgabetyp der Bind nur 'c->'b ist. -Es scheint es zu vereinfachen ('e->'f) zu nur c im Bind-Fall, oder fehlt mir hier etwas?

Danke für die Aufklärung,
tomas

Bearbeiten - Test dump:

let cReturn x = fun k -> k x 
let cBind m f = 
    printfn "cBind %A" <| m id 
    fun c -> m (fun a -> f a c) 

let map_fixed f xs = 
    let rec map xs = 
    printfn "map %A" xs 
    match xs with 
     | [] -> cReturn [] 
     | x :: xs -> cBind (fun c -> map xs c) (fun xs -> cReturn (f x :: xs)) 
    map xs (fun x -> x) 

let map f xs = 
    let rec map xs = 
    printfn "map %A" xs 
    match xs with 
     | [] -> cReturn [] 
     | x :: xs -> cBind (map xs) (fun xs -> cReturn (f x :: xs)) 
    map xs (fun x -> x) 

[1..2] |> map_fixed ((+) 1) |> printfn "%A" 
[1..2] |> map ((+) 1) |> printfn "%A" 

MAP_FIXED:
Karte [1; 2] map [2] map [] cbind [] map [] cbind [3] map [2] map [] cbind [] map [] [2; 3]

karte:
karte [1; 2] Karte [2] Karte [] cBind [] cBind [3] [2; 3]

Bearbeiten auf Frage 2:

let map f xs = 
    let rec map xs = 
     cont { 
      match xs with 
      | [] -> return [] 
      | x :: xs -> 
       let v = f x // Inference ok 
       //let! v = cont { return f x } // ! Inference issue - question 2 
       let! xs = map xs 
       return v :: xs 
     } 
    map xs id 
+0

In Bezug auf Ihre zweite Frage scheint Schlussfolgerung gut für mich zu funktionieren. – kvb

+0

Wenn ich das Kommentarzeichen entmarke // lass es ... gibt es mir: Typ stimmt nicht überein. Erwartet eine 'a aber eine a' a Liste gegeben – tomasK

+0

Ich sehe endlich den Fehler - war in meiner Bind-Definition - ähnlich Protokoll wie in Punkt 1 - albern mich, danke für Interesse. – tomasK

Antwort

3

Das Problem ist genau das fun c -> map xs cnicht ist die gleiche wie map xs. Sie haben in gewissem Sinne dieselbe "Bedeutung", aber ihre Laufzeit-Semantik ist unterschiedlich. Im letzteren Fall führt das Auswerten des Ausdrucks zu einem sofortigen Aufruf der map-Funktion mit xs als ein Argument (das eine andere Funktion als Ergebnis zurückgibt). Auf der anderen Seite führt die Auswertung fun c -> map xs cnicht zu einem sofortigen Aufruf an map! Der Aufruf an map wird verzögert, bis die resultierende Funktion tatsächlich angewendet wird. Dies ist der entscheidende Unterschied, der einen Stapelüberlauf verhindert.

In Bezug auf Ihre anderen Fragen, kann ich nicht richtig verstehen, was Sie in Ihrer zweiten Frage fragen. Für Ihre dritte Frage hat der Compiler den allgemeinsten möglichen Typ für Bind abgeleitet. Sie haben recht, dass der traditionelle Typ, den Sie erwarten könnten, spezifischer ist als dieser, aber es ist nicht wirklich ein Problem, dass Sie Bind in einem größeren Kontextsatz aufrufen können als unbedingt notwendig. Und wenn Sie einen spezifischeren Typ möchten, können Sie immer Anmerkungen hinzufügen, um die Signatur einzuschränken.

+0

In Bezug auf meine zweite Frage werden Sie sehen, was das Problem ist, wenn Sie versuchen, die Funktion dieser zweiten Op zu kompilieren - der Typ des Funktionsparameters ** f ** ist für mich unerwartet. – tomasK

+0

- "führt nicht zu einem sofortigen Aufruf der Karte" - aber nach meinem Test-Dump tut es - bevor der CBind ausgewertet wird - siehe meine Bearbeitung ... – tomasK

+1

@tomasK - Ihre Tests sind fehlerhaft, weil Sie 'm anwenden 'in Ihrem Logging von' cbind'. Ändere diese Zeile auf "printfn" cbind "' und du wirst sehen, dass 'map_fixed' wirklich verzögert den Aufruf von' map' verzögert. – kvb