开发者

F#: wrap single element to array

开发者 https://www.devze.com 2023-03-14 06:50 出处:网络
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|]|]; somet

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.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号