简体   繁体   English

F#类型匹配-无法创建地图或匹配记录

[英]F# Type Matching - Unable To Create Map Or Match Record

I have tried to adapt a WikiBooks example to accept csv input and types but am struggling with converting the incoming type list to a dictionary and matching user inputs. 我试图改编一个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

What am I missing? 我想念什么?

You need to use a tuple to create the Map from the List , so you don't really need the record type at all. 您需要使用一个元组从List创建Map ,因此您根本不需要记录类型。 Then, you will want to match on Map.tryFind of the input country. 然后,您将要在输入国家/地区的Map.tryFind上进行匹配。 Here's an example using the tuple and Map.tryFind . 这是使用元组和Map.tryFind The only other changes I made were to use printfn instead of Console.WriteLine and to simplify your list-generating expression: 我所做的唯一其他更改是使用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 To show continued use of record type: 编辑以显示记录类型的继续使用:

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."

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM