可变变量'指数'在seq {}中以无效的方式使用?

时间:2015-06-02 04:25:29

标签: f#

在以下代码中,编译器在index <- index + 1上收到错误

的错误
  

错误3可变变量&#39; index&#39;以无效的方式使用。闭包不能捕获可变变量。考虑通过&#39; ref&#39;来消除这种突变的使用或使用堆分配的可变参考单元。和&#39;。&#39;。 d:\ Users .... \ Program.fs 11 22 ConsoleApplication2

但是,它被定义为可变?

let rec iterateTupleMemberTypes (tupleArgTypes: System.Type[]) (columnNames: string[]) startingIndex = 
    seq {
        let mutable index = startingIndex
        for t in tupleArgTypes do
            match t.IsGenericType with
            | true -> iterateTupleMemberTypes (t.GetGenericArguments()) columnNames index |> ignore
            | false ->
                printfn "Name: %s Type: %A" (columnNames.[index]) t
                index <- index + 1
                yield (columnNames.[index]), t
    } |> Map.ofSeq

let myFile = CsvProvider<"""d:\temp\sample.txt""">.GetSample()
let firstRow = myFile.Rows |> Seq.head
let tupleType = firstRow.GetType()
let tupleArgTypes = tupleType.GetGenericArguments()
let m = iterateTupleMemberTypes tupleArgTypes myFile.Headers.Value 0

3 个答案:

答案 0 :(得分:2)

这个惯用版可能如下所示:

#r @"..\packages\FSharp.Data.2.2.2\lib\net40\FSharp.Data.dll"

open FSharp.Data
open System

type SampleCsv = CsvProvider<"Sample.csv">

let sample = SampleCsv.GetSample()

let rec collectLeaves (typeTree : Type) =
    seq {
        match typeTree.IsGenericType with
        | false -> yield typeTree.Name
        | true -> yield! typeTree.GetGenericArguments() |> Seq.collect collectLeaves
    }

let columnTypes = (sample.Rows |> Seq.head).GetType() |> collectLeaves

let columnDefinitions = columnTypes |> Seq.zip sample.Headers.Value |> Map.ofSeq

let getDefinitions (sample : SampleCsv) = (sample.Rows |> Seq.head).GetType() |> collectLeaves |> Seq.zip sample.Headers.Value |> Map.ofSeq

就个人而言,除非有数百列,否则我不会过分担心Map vs Dictionary的性能(而是拥有不可变的Map)。 / p>

答案 1 :(得分:1)

它之后的语句let index = 0会影响你对可变变量index的定义。此外,要使mutable按序列工作,您需要refs。 https://msdn.microsoft.com/en-us/library/dd233186.aspx

答案 2 :(得分:0)

@ Ming-Tang建议,我将可变变量更改为ref,现在可以正常使用了。但是,它是不是一种不使用mutable / ref变量的方法吗?

let rec iterateTupleMemberTypes (tupleArgTypes: System.Type[]) (columnNames: string[]) startingIndex = 
    seq {
        let index = ref startingIndex
        for t in tupleArgTypes do
            match t.IsGenericType with
            | true ->
                yield! iterateTupleMemberTypes (t.GetGenericArguments()) columnNames !index
            | false ->
                printfn "Name: %s Type: %A" (columnNames.[!index]) t
                yield (columnNames.[!index]), t
                index := !index + 1
    } |> dict

let myFile = CsvProvider<"""d:\temp\sample.txt""">.GetSample()
let firstRow = myFile.Rows |> Seq.head
let tupleType = firstRow.GetType()
let tupleArgTypes = tupleType.GetGenericArguments()
let m = iterateTupleMemberTypes tupleArgTypes myFile.Headers.Value 0