在F#中,如何使函数wrapper (x:'T)
将任何输入包装到数组数组中,比如:wrapper(1) = [|[|1|]|]; wrapper([|1|]) = [|[|1|]|]; and wrapper([|[|1|]|]) = [|[|1|]|];
类似下面的内容不起作用:
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 :(得分: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>>
。
回应你的评论:这种事情可以用静态类型语言完成 - 并且可以说比动态语言更好 - 但是/因为在类型系统之外的步进必须是明确的(例如,{{ 1}} / box
)。
答案 1 :(得分: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|]|]
答案 2 :(得分:1)
你不能,这不是一个很好的类型的函数(尝试写出类型签名)。
答案 3 :(得分:-1)
您的功能需要“将任何输入包装到数组数组中”。与此声明相同,解决方案非常简单:
let wrapper (x:'T) = [|[|x|]|];
但是你给出的例子不是你的函数定义。
即wrapper([|1|]) = [|[|1|]|]
应该wrapper([|1|]) = [|[|[|1|]|]|]
与您的函数定义相同。