matlabdbuser
matlabdbuser

Reputation: 838

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([|[|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

Upvotes: 0

Views: 276

Answers (4)

Ankur
Ankur

Reputation: 33657

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.

Upvotes: -1

Stephen Swensen
Stephen Swensen

Reputation: 22307

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|]|]

Upvotes: 2

Daniel
Daniel

Reputation: 47914

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).

Upvotes: 4

Brian
Brian

Reputation: 118895

You can't, that's not a well-typed function (try to write out the type signature).

Upvotes: 1

Related Questions