2009-06-02 11 views
5

Sto cercando di lavorare attraverso un esempio in Expert F #, che si basa su v1.9.2, ma le versioni CTP, dopo che hanno cambiato abbastanza che alcuni di loro non hanno nemmeno compilare più.Expert F # esempio web crawler

Sono in difficoltà con l'elenco 13-13. Ecco il frammento di definizione urlCollector oggetto:

let urlCollector = 
    MailboxProcessor.Start(fun self -> 
     let rec waitForUrl (visited : Set<string>) = 
      async { if visited.Count < limit then 
         let! url = self.Receive() 
         if not (visited.Contains(url)) then 
          do! Async.Start 
           (async { let! links = collectLinks url 
             for link in links do 
             do self <-- link }) 

         return! waitForUrl(visited.Add(url)) } 

      waitForUrl(Set.Empty)) 

Sto compilando con la versione 1.9.6.16 , e il compilatore si lamenta così:

  1. costrutto incompleta strutturato in corrispondenza o prima di questo punto in espressione [dopo l'ultimo paren]
  2. errore nell'espressione di ritorno per questo 'let'. Possibile indentazione errata [si riferisce alla definizione let di waitForUrl]

Qualcuno può vedere cosa sta succedendo qui?

risposta

3

Sembra che l'ultima riga debba essere 4 spaziati.

EDIT: in realtà, sembra che stia succedendo di più qui. Supponendo che questo è lo stesso campione come here, allora ecco una versione Ho appena modificato per essere in sincronia con l'uscita 1.9.6.16:

open System.Collections.Generic 
open System.Net 
open System.IO 
open System.Threading 
open System.Text.RegularExpressions 

let limit = 10  

let linkPat = "href=\s*\"[^\"h]*(http://[^&\"]*)\"" 
let getLinks (txt:string) = 
    [ for m in Regex.Matches(txt,linkPat) -> m.Groups.Item(1).Value ] 

let (<--) (mp: MailboxProcessor<_>) x = mp.Post(x) 

// A type that helps limit the number of active web requests 
type RequestGate(n:int) = 
    let semaphore = new Semaphore(initialCount=n,maximumCount=n) 
    member x.AcquireAsync(?timeout) = 
     async { let! ok = semaphore.AsyncWaitOne(?millisecondsTimeout=timeout) 
       if ok then 
        return 
        { new System.IDisposable with 
         member x.Dispose() = 
          semaphore.Release() |> ignore } 
       else 
        return! failwith "couldn't acquire a semaphore" } 

// Gate the number of active web requests 
let webRequestGate = RequestGate(5) 

// Fetch the URL, and post the results to the urlCollector. 
let collectLinks (url:string) = 
    async { // An Async web request with a global gate 
      let! html = 
       async { // Acquire an entry in the webRequestGate. Release 
         // it when 'holder' goes out of scope 
         use! holder = webRequestGate.AcquireAsync() 

         // Wait for the WebResponse 
         let req = WebRequest.Create(url,Timeout=5) 

         use! response = req.AsyncGetResponse() 

         // Get the response stream 
         use reader = new StreamReader(
          response.GetResponseStream()) 

         // Read the response stream 
         return! reader.AsyncReadToEnd() } 

      // Compute the links, synchronously 
      let links = getLinks html 

      // Report, synchronously 
      do printfn "finished reading %s, got %d links" 
        url (List.length links) 

      // We're done 
      return links } 

let urlCollector = 
    MailboxProcessor.Start(fun self -> 
     let rec waitForUrl (visited : Set<string>) = 
      async { if visited.Count < limit then 
         let! url = self.Receive() 
         if not (visited.Contains(url)) then 
          Async.Start 
           (async { let! links = collectLinks url 
             for link in links do 
              do self <-- link }) 
         return! waitForUrl(visited.Add(url)) } 

     waitForUrl(Set.Empty)) 

urlCollector <-- "http://news.google.com" 
// wait for keypress to end program 
System.Console.ReadKey() |> ignore 
+0

D'accordo ... a volte blocco di definizione da rientro è più oscura che utile. Ho preso l'abitudine di aggiungere i token di inizio/fine per avviare l'inizio e la fine di blocchi lunghi o profondamente annidati. Non sono richiesti nella sintassi #light ma sono ancora disponibili. – flatline

+0

Grazie - Farò una prova. Immagino che una cosa che è stata fuorviante, e la cosa più sfortunata data l'importanza di una corretta indentazione, è che l'esempio nel libro si estende su un'interruzione di pagina, quindi è difficile dire dove si allinea la rientranza. –

+0

Questo è stato interrotto di nuovo :( – Benjol