2011-06-21 77 views
0

,如何使一個功能wrapper (x:'T)封裝任意輸入數組的數組,說:wrapper(1) = [|[|1|]|]; wrapper([|1|]) = [|[|1|]|]; and wrapper([|[|1|]|]) = [|[|1|]|];類似下面不工作:F#:在F#換單元素數組

let wrapper (x:'T) = 
    let y = 
     if not <| x.GetType().IsArray then [|[|x|]|] 
     elif not <| x.[0].GetType().IsArray then [|x|] 
     else x 
    y 
+0

如果你想在F#中這樣做,你可能做錯了什麼。 – Laurent

回答

1

你不能,這不是一個很好的類型函數(嘗試寫出類型簽名)。

+0

謝謝。像Python這樣的動態類型語言是否允許這樣的功能? – matlabdbuser

+0

@matlabdbuser - 任何.NET語言都可以使用'System.Reflection'完成大部分典型的動態語言。而現在,隨着.NET 4.0中的DLR以及C#的靜態'動態'和F#''''操作符等內置語言特性,差距更加緊密。 –

+1

@matlabdbuser - 正如其他一些答案所顯示的,只要給函數一個相對無用的類型(例如'obj-> obj'或''a - >''),就可以讓它在F#中工作。 b [] []')。對我來說,問題是爲什麼你會想要一個這樣做的函數。如果你反對類型系統的努力,這通常表明,如果你退後一步並分析你的需求,有一種更習慣的方式來解決你的問題。 – kvb

4

以下似乎工作:

let wrapper<'a, 'b> (x:'a) = 
    match box x with 
    | null -> null 
    | :? array<array<'b>> as y -> y 
    | :? array<'b> as y -> [|y|] 
    | y -> [|[|unbox y|]|] 

簽名是'a -> array<array<'b>>

迴應你的評論:這類事情可以用靜態類型語言來完成 - 而且可以說比動態語言更好 - 但是/因爲跨越類型系統必須是明確的(例如,box/unbox)。

2

這裏的一個基於反射溶液將接受任意嵌套陣列深度的輸入:

open System.Text.RegularExpressions 
let wrapper input = 
    let ty = input.GetType() 
    if ty.IsArray |> not then 
     [|[|input |> unbox|]|] 
    else 
     let depth = Regex.Matches(ty.Name, "\[\]", RegexOptions.Compiled).Count 
     let rec findInnerItem curDepth curArray = 
      let innerItem = curArray.GetType().GetMethod("Get").Invoke(curArray, [|box 0|]) 
      if curDepth = depth then 
       innerItem 
      else 
       findInnerItem (curDepth+1) innerItem 

     let innerItem = findInnerItem 1 input 
     [|[|innerItem |> unbox|]|] 

用法在FSI:

val wrapper : 'a -> 'b [] [] 

> let x : int[][] = wrapper 1;; 

val x : int [] [] = [|[|1|]|] 

> let x : int[][] = wrapper [|1|];; 

val x : int [] [] = [|[|1|]|] 

> let x : int[][] = wrapper [|[|1|]|];; 

val x : int [] [] = [|[|1|]|] 

> let x : int[][] = wrapper [|[|[|1|]|]|];; 

val x : int [] [] = [|[|1|]|] 

> let x : int[][] = wrapper [|[|[|[|1|]|]|]|];; 

val x : int [] [] = [|[|1|]|] 

> let x : int[][] = wrapper [|[|[|[|[|1|]|]|]|]|];; 

val x : int [] [] = [|[|1|]|] 

> let x : int[][] = wrapper [|[|[|[|[|[|1|]|]|]|]|]|];; 

val x : int [] [] = [|[|1|]|] 
-1

您函數需要「包裝的任何輸入到陣列的陣列」。作爲比肩這種說法的解決方案是非常簡單:

let wrapper (x:'T) = [|[|x|]|]; 

但你必須給出的例子並不像你看齊函數定義。 即wrapper([|1|]) = [|[|1|]|]應該是wrapper([|1|]) = [|[|[|1|]|]|]作爲您的函數定義。