2014-01-14 68 views
1

泛型和鑄造用在以下方式問題在F#

type Genome<'T> (listIn : List<'T>)= 
    member this.list = listIn 
    member this.GetValues() = 
     this.list 

我遇到了一個問題,而寫另一個代碼段實施了基因組型。

type IMutation = 
    abstract member MutateMethod: Genome<'T> -> Genome<'T> 

type DoubleGenomeMutation() = 
    member this.Mutate = (this :> IMutation).MutateMethod 
    interface IMutation with 
     member this.MutateMethod(genome: Genome<'T>) = 
      let randomIndex = MyRandom.Next(0, genome.list.Length) 
      printfn "%d" randomIndex 
      let newValue = MyRandom.NextDouble(Parameters.LowerBounds.Item(randomIndex), Parameters.UpperBounds.Item(randomIndex)) 

      let (newGenomeList : List<'double>, _) = 
       List.foldBack (fun elem acc -> 
       match acc with 
       | (l, 0) -> (newValue::l, -1) 
       | (l, i) -> (elem::l, i-1)) (genome.GetValues()) ([], genome.GetValues().Length - randomIndex - 1) 

      new Genome<'T>(newGenomeList) 

我發現不可能在這裏正確使用泛型機制。在

Error 2 Type mismatch. Expecting a 
    float list  
but given a 
    List<'a>  
The type 'float' does not match the type ''a' 

引述的樣本效應線

| (l, i) -> (elem::l, i-1)) (genome.GetValues()) ([], genome.GetValues().Length - randomIndex - 1) 

鑄造變量朝上或朝下ofter描述爲類似案件的解決方案 - 不幸的是我無法修復我的這樣的程序。我將不勝感激任何直接幫助以及任何有關所有問題根源的建議。

+1

我打賭你有一個'System.Collections中開放.Generic'在頂部,並與列表類型產生混淆 –

+0

可能根本不是。我沒有在任何地方使用System.Collections.Generic,只有不可變的F#列表。 –

+0

如果將簽名從「列表<'a>」更改爲「列表」,會發生什麼情況? –

回答

2

我沒有的MyRandom源,但如果我有int取代MyRandom.Next因爲它看起來像它應該是和一個double替換MyRandom.Double,那麼我可以重現你的錯誤。

問題是MyRandom.NextDouble的返回類型會不當地限制其餘代碼; MutateMethod被聲明能夠採取任何類型的參數,但是然後您使用newValue作爲(l, 0)情況下的返回列表的一部分,這也限制了另一種情況的類型。

您可能還從newValue得到了一個警告,指出它將您的'double類型變量限制爲float這是另一個線索。真的'double應該是'T,因爲這是該參數最初聲明的方式。

錯誤消失,如果我更換呼叫MyRandom.NextDouble與拋出異常(可以有任何結果類型),這證實了這一診斷:

type DoubleGenomeMutation() = 
    member this.Mutate = (this :> IMutation).MutateMethod 
    interface IMutation with 
     member this.MutateMethod(genome: Genome<'T>) = 
      let randomIndex = 1 // MyRandom.Next(0, genome.list.Length) 
      printfn "%d" randomIndex 
      let newValue = failwith "foo" 

      let (newGenomeList : List<'T>, _) = 
       List.foldBack (fun elem acc -> 
       match acc with 
       | (l, 0) -> (newValue::l, -1) 
       | (l, i) -> (elem::l, i-1)) (genome.GetValues()) ([], genome.GetValues().Length - randomIndex - 1) 

      new Genome<'T>(newGenomeList) 
+0

非常感謝。似乎如果我按照我的方式指定了'IMutation'接口,任何實現都必須能夠處理任何'T類型。但是有什麼解決方案可以允許使用多個專門的實現(例如:一個只用於雙打,一個用ints等 - 內部有不同的邏輯)? –

+2

最乾淨的方法是定義'IMutation'接口的多個'MutateMethod'成員 - 我認爲你可以共享名重載決議應該能夠明白這一點。你也可以用一個大的匹配語句來實現'MutateMethod',它會進行類型測試,但是它需要大量的裝箱和取消裝箱來安撫類型檢查器。 –