Reputation: 29159
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
Upvotes: 0
Views: 122
Reputation: 8551
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.
Upvotes: 2
Reputation: 29159
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
Upvotes: 0
Reputation: 17651
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
Upvotes: 1