F#: wrap single element to array
in F#, How to make a function wrapper (x:'T)
to wrap any inputs to an array of array, say: wrapper(1) = [|[|1|]|]; wrapper([|1|]) = [|[|1|]|]; and wrapper开发者_JAVA百科([|[|1|]|]) = [|[|1|]|];
something like below does not work:
let wrapper (x:'T) =
let y =
if not <| x.GetType().IsArray then [|[|x|]|]
elif not <| x.[0].GetType().IsArray then [|x|]
else x
y
The following seems to work:
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|]|]
The signature is 'a -> array<array<'b>>
.
In response to your comment: this sort of thing can be done in statically-typed languages--and, arguably better than in a dynamic language--but/because stepping outside the type system must be explicit (e.g., box
/unbox
).
Here's a reflection based solution which will accept inputs of arbitrary nested array depth:
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|]|]
Usage in 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|]|]
You can't, that's not a well-typed function (try to write out the type signature).
You function needs to "wrap any inputs to an array of array". As par this statement the solution is as simple as:
let wrapper (x:'T) = [|[|x|]|];
But then the examples you have given are not as par your function definition.
i.e wrapper([|1|]) = [|[|1|]|]
should be wrapper([|1|]) = [|[|[|1|]|]|]
as par your function definition.
精彩评论