我的第一个F#计划

sud*_*aly 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
Run Code Online (Sandbox Code Playgroud)

Tom*_*cek 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
Run Code Online (Sandbox Code Playgroud)

使用它的代码将改变如下:

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
Run Code Online (Sandbox Code Playgroud)

EstablishConnection函数中,您绝对不需要声明一个可变变量sr,因为在异常的情况下,函数将返回null.我会改用option类型来确保处理这种情况:

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 
Run Code Online (Sandbox Code Playgroud)

可以使用在EstablishConnection失败时停止的递归函数来编写主循环:

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