【问题标题】:F# Type Matching - Unable To Create Map Or Match RecordF# 类型匹配 - 无法创建映射或匹配记录
【发布时间】:2018-05-17 14:50:12
【问题描述】:

我试图调整一个 WikiBooks 示例以接受 csv 输入和类型,但在将传入的类型列表转换为字典并匹配用户输入方面遇到了困难。

// https://en.wikibooks.org/wiki/F_Sharp_Programming/Sets_and_Maps#Examples_2

module SOQN = 

   open System
   open FSharp.Data

   type Country = Country of string
   type City = City of string
   type CountryCapital = {
      Country:Country
      City:City 
    }
   let [<Literal>] sampleCsv  = @"D:\Country_Capitals.csv"
   type Capitals = CsvProvider<sampleCsv, Separators=",", HasHeaders=true>

   let readFromCsvFile (fileName:string) = 
      let data = Capitals.Load(fileName)
      [ for row in data.Rows do
           yield { Country = Country row.Country; City = City row.City; } ]        
   let countryCapitals = 
      readFromCsvFile sampleCsv
   // ->     |> Map.ofList

   Console.Write("Find capital by country (type 'q' to quit): ")
   match Console.ReadLine() with
   | "q" -> Console.WriteLine("Bye!")
   | country ->
      match countryCapitals with
      // ->     | { Country = country } -> Console.WriteLine("Capital of {0} is {1}\n", country, capital)
      | _ -> Console.WriteLine("Country not found.\n")

  // Expected Output: Find capital by country (type 'q' to quit): Egypt
  //                  Capital of Egypt is Cairo

我错过了什么?

【问题讨论】:

    标签: dictionary types f# pattern-matching


    【解决方案1】:

    您需要使用元组从List 创建Map,因此您根本不需要记录类型。然后,您将要匹配输入国家/地区的Map.tryFind。这是一个使用元组和Map.tryFind 的示例。我所做的唯一其他更改是使用 printfn 而不是 Console.WriteLine 并简化您的列表生成表达式:

    open System
    open FSharp.Data
    
    let [<Literal>] sampleCsv  = @"D:\Country_Capitals.csv"
    type Capitals = CsvProvider<sampleCsv, Separators=",", HasHeaders=true>
    
    let readFromCsvFile (fileName:string) = 
        let data = Capitals.Load(fileName)
        [ for row in data.Rows -> (row.Country, row.City) ]    
    
    let countryCapitals = 
        readFromCsvFile sampleCsv
        |> Map.ofList
    
    printfn "Find capital by country (type 'q' to quit): "
    
    match Console.ReadLine() with
    | "q" -> printfn "Bye!"
    | country ->
        match countryCapitals |> Map.tryFind country with
        | Some capital -> printfn "Capital of %s is %s" country capital
        | _ -> printfn "Country not found."
    

    EDIT 显示继续使用记录类型:

    open System
    open FSharp.Data
    
    type CountryCaptial = { Country: string; Capital: string }
    
    let [<Literal>] sampleCsv  = @"D:\Country_Capitals.csv"
    type Capitals = CsvProvider<sampleCsv, Separators=",", HasHeaders=true>
    
    let readFromCsvFile (fileName:string) = 
        let data = Capitals.Load(fileName)
        [ for row in data.Rows -> { Country = row.Country; Capital = row.City } ]    
    
    let countryCapitals = 
        readFromCsvFile sampleCsv
        |> List.map (fun c -> c.Country, c)
        |> Map.ofList
    
    printfn "Find capital by country (type 'q' to quit): "
    
    match Console.ReadLine() with
    | "q" -> printfn "Bye!"
    | country ->
        match countryCapitals |> Map.tryFind country with
        | Some countryCapital -> printfn "Capital of %s is %s" countryCapital.Country countryCapital.Capital
        | _ -> printfn "Country not found."
    

    【讨论】:

    • 谢谢@AaronMEshbach。是否有解决方案来包含我的记录类型,因为我需要提高对类型和用户交互的理解?
    • 您可以保留记录类型,但在此示例中并没有增加太多价值。我已经编辑了我的答案,以包含使用您的记录类型的第二个示例。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-29
    • 2020-10-21
    • 2013-10-19
    • 2015-04-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多