I reported this as a potential bug to fsbugs and received a response from Brian that this sort of lazy type resolution is not possible within F#. Thus, this optimization is no optimization in F#. See this topic for details on a more idiomatic iteratee implementation.
Topic tags
- f# × 3586
- compiler × 262
- functional × 199
- c# × 117
- classes × 96
- web × 94
- book × 83
- .net × 80
- websharper × 75
- async × 71
- server × 43
- parallel × 42
- parsing × 41
- testing × 41
- asynchronous × 29
- monad × 28
- ocaml × 26
- tutorial × 26
- haskell × 25
- workflows × 21
- html × 20
- introduction × 19
- linq × 19
- wpf × 19
- silverlight × 18
- collections × 14
- pipeline × 14
- fpish × 13
- templates × 12
- monads × 11
- opinion × 10
- plugin × 9
- reactive × 9
- scheme × 9
- solid × 9
- basics × 8
- concurrent × 8
- deployment × 8
- how-to × 8
- sitelets × 8
- complexity × 7
- python × 7
- javascript × 6
- lisp × 6
- real-world × 6
- workshop × 6
- xaml × 6
- conference × 5
- dsl × 5
- java × 5
- ml × 5
- scala × 5
- formlets × 4
- jquery × 4
- lift × 4
- metaprogramming × 4
- teaching × 4
- alt.net × 3
- aml × 3
- enhancement × 3
- reflection × 3
- compilation × 2
- computation expressions × 2
- corporate × 2
- cufp × 2
- enterprise × 2
- erlang × 2
- http × 2
- interactive × 2
- interface × 2
- iphone × 2
- iteratee × 2
- jobs × 2
- keynote × 2
- numeric × 2
- obfuscation × 2
- oop × 2
- packaging × 2
- pipelines × 2
- sockets × 2
- stm × 2
- tcp × 2
- type provider × 2
- visual studio × 2
- .net interop × 1
- abstract class × 1
- agents × 1
- agile × 1
- appcelerator × 1
- asp.net mvc 4 × 1
- asp.net web api × 1
- ast × 1
- b-tree × 1
- bistro × 1
- blog × 1
- bug × 1
- client × 1
- cloud × 1
- continuation-passing style × 1
- css × 1
- data × 1
- database × 1
- declarative × 1
- dhtmlx × 1
- documentation × 1
- dol × 1
- domain × 1
- eclipse × 1
- em algorithm × 1
- emacs × 1
- emotion × 1
- error × 1
- example × 1
- extension methods × 1
- fear × 1
- fp × 1
- functional style × 1
- gc × 1
- generic × 1
- geometry × 1
- getlastwin32error × 1
- hash × 1
- history × 1
- html5 × 1
- httpcontext × 1
- hubfs × 1
- installer × 1
- interpreter × 1
- io × 1
- ios × 1
- ipad × 1
- kendo × 1
- licensing × 1
- list × 1
- macro × 1
- macros × 1
- marshal × 1
- math × 1
- metro style × 1
- micro orm × 1
- minimum-requirements × 1
- multithreading × 1
- nancy × 1
- nested loops × 1
- object relation mapper × 1
- object-oriented × 1
- offline × 1
- option × 1
- orm × 1
- osx × 1
- pattern matching × 1
- performance × 1
- phonegap × 1
- programming × 1
- quant × 1
- range × 1
- raphael × 1
- real-time × 1
- restful × 1
- round table × 1
- runtime × 1
- rx × 1
- script × 1
- session-state × 1
- sitelet × 1
- sql × 1
- stickynotes × 1
- stress × 1
- structures × 1
- tdd × 1
- trie × 1
- type × 1
- type providers × 1
- upload × 1
- vector × 1
- visual f# × 1
- visual studio shell × 1
- windows-phone × 1
- winrt × 1
- xna × 1
![]() |
Copyright (c) 2011-2012 IntelliFactory. All rights reserved. Home | Products | Consulting | Trainings | Blogs | Jobs | Contact Us | Built with WebSharper |


If any of you would be willing to take a look, I would really appreciate it. The current code follows:
module FSharp.Monad.Iteratee.CPS open System [<CustomEquality>] [<NoComparison>] // TODO: Implement IStructuralComparable type Stream<'a when 'a : equality> = | Chunk of 'a | Empty | EOF of exn option override x.Equals(y) = if y.GetType() <> typeof<Stream<_>> then false else let y = unbox<Stream<_>> y in match x, y with | Chunk c1, Chunk c2 -> c1 = c2 | EOF None, EOF None -> true | EOF (Some e1), EOF (Some e2) -> true | _ -> false override x.GetHashCode() = // TODO: Real implementation of GetHashCode() match x with | Empty -> 0 | Chunk xs -> xs.GetHashCode() | EOF e -> e.GetHashCode() module Stream = let map f = function | Chunk xs -> Chunk (f xs) | s -> s type IterateeCPS<'el,'a,'r when 'el : equality> = Iteratee of (('a -> Stream<'el> -> 'r) -> ((Stream<'el> -> IterateeCPS<'el,'a,'r>) -> exn option -> 'r) -> 'r) type EnumeratorCPS<'el,'a,'r when 'el : equality> = IterateeCPS<'el,'a,IterateeCPS<'el,'a,'r>> -> IterateeCPS<'el,'a,'r> type EnumerateeCPS<'eli,'elo,'a,'r when 'elo:equality and 'eli:equality> = IterateeCPS<'eli,'a,IterateeCPS<'elo,IterateeCPS<'eli,'a,'r>,'r>> -> IterateeCPS<'elo,IterateeCPS<'eli,'a,'r>,'r> [<AutoOpen>] module Primitives = let runIter (Iteratee i) onDone onCont = i onDone onCont let doneI x str = Iteratee <| fun onDone _ -> onDone x str let contI k e = Iteratee <| fun _ onCont -> onCont k e let liftI k = Iteratee <| fun _ onCont -> onCont k None let rec fmap f m = Iteratee <| fun onDone onCont -> let od = onDone << f let oc k e = onCont (fun s -> fmap f (k s)) e runIter m od oc let returnI x = Iteratee <| fun onDone _ -> onDone x Empty let bind (m: IterateeCPS<'el,'a,'r>) (f: 'a -> IterateeCPS<'el,'b,'r>) : IterateeCPS<'el,'b,'r> = let rec inner m f = Iteratee <| fun onDone onCont -> let mdone a s = let fcont k = function | None -> runIter (k s) onDone onCont | Some e -> onCont k (Some e) in match s with | Empty -> runIter (f a) onDone onCont | _ -> runIter (f a) (fun x _ -> onDone x s) fcont in runIter m mdone (fun k e -> onCont (fun s -> inner (k s) f) e) inner m f let inline (>>=) m f = bind m f let inline (<*>) f m = f >>= fun f' -> fmap f' m let run i = let rec onDone x _ = x and onCont k = function | None -> runIter (k (EOF None)) onDone onCont' | Some e -> raise e and onCont' k = function | None -> failwith "divergent iteratee" | Some e -> raise e in runIter i onDone onCont let tryRun i = let rec onDone x _ = Choice1Of2 x and onCont k = function | None -> runIter (k (EOF None)) onDone onCont' | Some e -> Choice2Of2 e and onCont' k = function | None -> Choice2Of2 (Exception("divergent iteratee")) | Some e -> Choice2Of2 e in runIter i onDone onCont let either f g = function | Choice1Of2 x -> f x | Choice2Of2 y -> g y let rec lift f i = Iteratee <| fun onDone onCont -> let od a str = Choice1Of2(a,str) let oc k e = Choice2Of2(lift f << k, e) f (runIter i od oc) >>= either (fun (a,b) -> onDone a b) (fun (k,e) -> onCont k e) let rec throw e = contI (fun _ -> throw e) (Some e) let throwRecoverable e i = contI i (Some e) let rec checkErr i = Iteratee <| fun onDone onCont -> let od = onDone << Choice2Of2 let oc k = function | None -> onCont (checkErr << k) None | Some e -> onDone (Choice1Of2 e) Empty runIter i od oc let identity<'a when 'a : equality> = doneI () (Empty:Stream<'a>) let skipToEof<'a when 'a : equality> = let rec loop() = let check = function | Chunk _ -> loop() | s -> doneI () (s:Stream<'a>) in contI check None loop () let joinI outer = bind outer (fun inner -> Iteratee <| fun onDone onCont -> let od x _ = onDone x Empty let rec oc k = function | None -> runIter (k (EOF None)) od oc' | Some e -> runIter (throw e) onDone onCont and oc' _ e = runIter (throw (Exception("divergent iteratee"))) onDone onCont runIter inner od oc) // let enumEOF i = // let rec onDone x _ = doneI x (EOF None) // and onCont k = function // | None -> runIter (k (EOF None)) onDone onCont' // | Some e -> contI k e // and onCont' k = function // | None -> throw (Exception("divergent iteratee")) // | Some e -> contI k e // in runIter i onDone onCont // // let enumErr e i = // let rec onDone x _ = doneI x (EOF (Some e)) // and onCont k = function // | None -> runIter (k (EOF (Some e))) onDone onCont' // | Some e' -> contI k e' // and onCont' k = function // | None -> throw (Exception("divergent iteratee")) // | Some e' -> contI k e' // in runIter i onDone onCont type IterateeCPSBuilder() = member this.Return(x) = returnI x member this.ReturnFrom(m:IterateeCPS<_,_,_>) = m member this.Bind(m, k) = bind m k member this.Zero() = returnI () member this.Combine(comp1, comp2) = bind comp1 (fun () -> comp2) member this.Delay(f) = bind (returnI ()) f let iterateeCPS = IterateeCPSBuilder()