title: Lazy.. but eager data loader in F#
body: <p>Does anyone know of 'prior art' regarding the following subject :</p>
  
  <ul>
  <li>I have data that take some decent time to load. they are historical level for various stocks. </li>
  <li>I would like to preload them somehow, to avoid the latency when using my app</li>
  <li>However, preloading them in one chunk at start makes my app unresponsive first which is not user friendly</li>
  </ul>
  
  <p>So I would like to <em>not</em> load my data.... <em>unless</em> the user is not requesting any and playing with what he already has, in which case I would like to get little by little. So it is neither 'lazy' nor 'eager', more 'lazy when you need' and 'eager when you can', hence the acronym LWYNEWYC.</p>
  
  <p>I have made the following which seems to work, but I just wonder if there is a recognized and blessed approach for such thing ?</p>
  
  <pre><code>let r = LoggingFakeRepo () :&gt; IQuoteRepository
  r.getHisto "1" |&gt; ignore  //prints Getting histo for 1 when called
  
  let rc =  RepoCached (r) :&gt; IQuoteRepository
  rc.getHisto "1" |&gt; ignore //prints Getting histo for 1 the first time only
  
  let rcc =  RepoCachedEager (r) :&gt; IQuoteRepository
  rcc.getHisto "100" |&gt; ignore  //prints Getting histo 1..100 by itself BUT
                                //prints Getting histo 100 immediately when called
  </code></pre>
  
  <p>And the classes </p>
  
  <pre><code>type IQuoteRepository = 
     abstract getUnderlyings : string seq
     abstract getHisto :  string -&gt; string
  
  type LoggingFakeRepo () =
     interface IQuoteRepository with 
        member x.getUnderlyings = printfn "getting underlyings"
                                  [1 .. 100] |&gt; List.map string :&gt; _
  
        member x.getHisto udl = printfn "getting histo for %A" udl
                                "I am a historical dataset in a disguised party"
  
  type RepoCached (rep : IQuoteRepository) =
     let memoize f =
       let cache = new System.Collections.Generic.Dictionary&lt;_, _&gt;()
       fun x -&gt;
          if cache.ContainsKey(x) then cache.[x]
          else let res = f x
               cache.[x] &lt;- res
               res
     let udls = lazy (rep.getUnderlyings )
     let gethistom = memoize rep.getHisto
  
     interface IQuoteRepository with 
        member x.getUnderlyings = udls.Force()
        member x.getHisto udl = gethistom udl
  
  type Message = string * AsyncReplyChannel&lt;UnderlyingWrap&gt;
  type RepoCachedEager (rep : IQuoteRepository) =
     let udls = rep.getUnderlyings
  
     let agent = MailboxProcessor&lt;Message&gt;.Start(fun inbox -&gt;
        let repocached = RepoCached (rep) :&gt; IQuoteRepository
        let rec loop l =
           async {  try
                       let timeout = if l|&gt; List.isEmpty  then -1 else 50
                       let! (udl, replyChannel) = inbox.Receive(timeout)
                       replyChannel.Reply(repocached.getHisto udl)
                       do! loop l
                    with 
                    | :? System.TimeoutException -&gt; 
                       let udl::xs = l
                       repocached.getHisto udl |&gt; ignore
                       do! loop xs
            }
        loop (udls |&gt; Seq.toList))
  
     interface IQuoteRepository with 
        member x.getUnderlyings = udls
        member x.getHisto udl = agent.PostAndReply(fun reply -&gt; udl, reply)
  </code></pre>