The mutable variable 'index' is used in an invalid way in seq {}?

有些话、适合烂在心里 提交于 2019-12-13 05:00:38

问题


In the following code, the compiler gets error on index <- index + 1 with error

Error 3 The mutable variable 'index' is used in an invalid way. Mutable variables cannot be captured by closures. Consider eliminating this use of mutation or using a heap-allocated mutable reference cell via 'ref' and '!'. d:\Users....\Program.fs 11 22 ConsoleApplication2

However, it has been defined as mutable?

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

回答1:


An idiomatic version of this might look like the following:

#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

Personally, I wouldn't be concerned too much about the performance of Map vs Dictionary (and rather have the immutable Map) unless there are hundreds of columns.




回答2:


The statement after it, let index = 0, shadows your definition of mutable variable index. Also, to make mutables work in sequences, you need refs. https://msdn.microsoft.com/en-us/library/dd233186.aspx




回答3:


Suggested by @Ming-Tang, I changed the mutable variable to ref and it works now. However, is it a way not to use mutable/ref variable at all?

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


来源:https://stackoverflow.com/questions/30587314/the-mutable-variable-index-is-used-in-an-invalid-way-in-seq

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!