2010-05-20 54 views
1

我剛寫完我的第一個F#程序。功能明智的代碼以我想要的方式工作,但不知道代碼是否有效。我將非常感激,如果有人可以審查我的代碼,並指出其中的代碼可以改進的地方。我的第一個F#程序

感謝 Sudaly

open System 
open System.IO 
open System.IO.Pipes 
open System.Text 
open System.Collections.Generic 
open System.Runtime.Serialization 


[<DataContract>] 
type Quote = { 
    [<field: DataMember(Name="securityIdentifier") >] 
    RicCode:string 
    [<field: DataMember(Name="madeOn") >] 
    MadeOn:DateTime 
    [<field: DataMember(Name="closePrice") >] 
    Price:float 
    } 

let m_cache = new Dictionary<string, Quote>() 

let ParseQuoteString (quoteString:string) = 
    let data = Encoding.Unicode.GetBytes(quoteString) 
    let stream = new MemoryStream() 
    stream.Write(data, 0, data.Length); 
    stream.Position <- 0L 
    let ser = Json.DataContractJsonSerializer(typeof<Quote array>) 
    let results:Quote array = ser.ReadObject(stream) :?> Quote array 
    results 

let RefreshCache quoteList = 
    m_cache.Clear() 
    quoteList |> Array.iter(fun result->m_cache.Add(result.RicCode, result)) 


let EstablishConnection() = 
    let pipeServer = new NamedPipeServerStream("testpipe", PipeDirection.InOut, 4) 
    let mutable sr = null 
    printfn "[F#] NamedPipeServerStream thread created, Wait for a client to connect" 
    pipeServer.WaitForConnection() 
    printfn "[F#] Client connected." 
    try 
     // Stream for the request. 
     sr <- new StreamReader(pipeServer) 
    with 
    | _ as e -> printfn "[F#]ERROR: %s" e.Message 
    sr 


while true do 
    let sr = EstablishConnection() 
    // Read request from the stream. 
    printfn "[F#] Ready to Receive data" 

    sr.ReadLine() 
    |> ParseQuoteString 
    |> RefreshCache 

    printfn "[F#]Quot Size, %d" m_cache.Count 
    let quot = m_cache.["MSFT.OQ"] 
    printfn "[F#]RIC: %s" quot.RicCode 
    printfn "[F#]MadeOn: %s" (String.Format("{0:T}",quot.MadeOn)) 
    printfn "[F#]Price: %f" quot.Price 
+1

你可能想解釋一下:

let EstablishConnection() = let pipeServer = new NamedPipeServerStream("testpipe", PipeDirection.InOut, 4) printfn "[F#] NamedPipeServerStream thread created..." pipeServer.WaitForConnection() printfn "[F#] Client connected." try // Wrap the result in 'Some' to denote success Some(new StreamReader(pipeServer)) with e -> printfn "[F#]ERROR: %s" e.Message // Return 'None' to denote a failure None 

主迴路可以使用時EstablishConnection失敗的情況下停止遞歸函數寫該代碼旨在做到這一點。 – 2010-05-20 20:29:31

回答

6

一般來說,你應該嘗試使用不可變的數據類型,並避免使用命令式結構,如全局變量和命令循環 - 儘管在F#中使用它們在很多情況下都很好,但只有在有充分的理由所以。這裏有幾個例子,你可以使用功能的方法:

所有的

首先,爲了使代碼更實用,你應該避免使用全局可變緩存。相反,您的RefreshCache函數應該返回數據作爲結果(優選使用一些功能性的數據結構,如F#Map型):

let PopulateCache quoteList = 
    quoteList 
    // Generate a sequence of tuples containing key and value 
    |> Seq.map (fun result -> result.RicCode, result) 
    // Turn the sequence into an F# immutable map (replacement for hashtable) 
    |> Map.ofSeq 

使用它會像這樣被改變的代碼:

let cache = 
    sr.ReadLine() 
    |> ParseQuoteString 
    |> PopulateCache 

printfn "[F#]Quot Size, %d" m_cache.Count 
let quot = m_cache.["MSFT.OQ"] 
// The rest of the sample stays the same 

EstablishConnection功能,你絕對不會需要聲明一個可變變量sr,因爲在異常的情況下,該函數將返回null。我會改用option類型,以確保這種情況下的處理:

let rec loop() = 
    match EstablishConnection() with 
    | Some(conn) -> 
     printfn "[F#] Ready to Receive data" 
     // rest of the code 
     loop() // continue looping 
    | _ ->() // Quit 
+0

哇...謝謝您的意見托馬斯,這是很有啓發 – sudaly 2010-05-20 22:06:35

1

乍一看它是寫在命令行式風格,而不是功能性的風格,這有一定道理,因爲大多數程序都涉及副作用(即I/O)。 Line for line,它幾乎看起來像一個C#程序。

鑑於正在發生的I/O數量,我不知道這是有很多可以做,以這種特殊的程序,使之更編碼的功能性風格。

+0

謝謝您的意見羅伯特 – sudaly 2010-05-20 20:54:45

3

只是一對夫婦的想法...

你可能需要一個「使用」,而不是「讓我們在幾個地方,因爲我認爲在一些程序中的對象是IDisposable

您可以考慮包裹EstablishConnection方法和最終while循環異步塊(並進行其他小的變化),因此如您可以異步等待連接而不阻塞線程。

+0

謝謝您的意見布萊恩,我會讓你建議的這些變化。 – sudaly 2010-05-20 20:56:38