f# - 如何编写类型安全的递归内联函数来展平元组

标签 f# inline

我想创建一个类型安全的递归函数来展平元组。 但是在类型安全方面我不能低于第一个递归级别

type Flatten = Flatten
with
    static member inline ($) (Flatten, (a: 'a, b: 'b)) : 'x list = 
        List.concat [ Flatten.Flat a; Flatten.Flat b]
    static member inline($) (Flatten, (a: 'a, b: 'b, c: 'c))  : 'x list = 
        List.concat [Flatten.Flat a; Flatten.Flat b; Flatten.Flat c]
    static member inline Flat(x: obj) : 'x list = 
        match x with
        | :? Tuple<'a, 'b> as t -> Flatten $ (t.Item1, t.Item2)
        | :? Tuple<'a, 'b, 'c> as t ->Flatten $ (t.Item1, t.Item2, t.Item3)
        | _ -> [x]
let inline flatten x  = Flatten $ x
let a1 = flatten (1, (2, 2, 3), (3,3))
//this compiles 
let a2 = flatten (1, (2, 2, 3, 4), (3,3))
//                             ^ but this too

我尝试了另一种方法

type Flatten = Flatten
with
    static member inline ($) (Flatten, (a: 'a, b: 'b)) = List.concat [ Flat $ a; Flat $ b]
    static member inline ($) (Flatten, (a: 'a, b: 'b, c: 'c)) = List.concat [Flat $ a; Flat $ b; Flat $ c]

and Flat = Flat
with
    static member inline ($) (Flat, a: 'a) = [a]
    static member inline ($) (Flat, x: ('a *'b)) = 
        let (a, b) = x
        List.concat [ Flatten $ a; Flatten $ b]
    static member inline($) (Flat, x : ('a * 'b * 'c)) = 
        let (a, b, c) = x
        List.concat [Flatten $ a; Flatten $ b; Flatten $ c]

let inline flatten x  = Flatten $ x
let a = flatten (1, 1)
let a1 = flatten (1, 1, 3)
let a2 = flatten (1, 1, (3, 3))

但我不能让那个类型检查。

有人知道吗?

一个附加要求

我做这一切的部分原因是我想

let a1 = flatten (1, (2, 2, 3), (3,3))

屈服

val a1 : int list

那是因为当我输入 int 元组的元组 时,唯一合理的结果应该是 int 列表。 此刻我得到一个 obj list int 第一个例子在第二个例子中出现编译错误。

最好的问候

最佳答案

.Net Tuple类(class)有arities from 1 to 8在其类型参数的数量。我相信在 F# 中,如果您有一个包含 8 个或更多元素的元组,它会被视为一个包含七个元素的元组加上一个位于八个槽中的嵌套元组,例如(a,b,c,d,e,f,g,h,i,j)真的是(a,b,c,d,e,f,g,(h,i,j)) , System.Tuple<'T1,'T2,'T3,'T4,'T5,'T6,'T7,System.Tuple<'T8,'T9,'T10>> 类型的元组.

但是,您的第一种方法仅处理 arity 2 和 3,但是当您执行 flatten (1, (2, 2, 3, 4), (3,3)) 时,您正在使用 arity-4 元组对其进行测试。 .如果您重写第一个 Flat 会怎样功能如下?

static member inline Flat(x: obj) : 'x list = 
    match x with
    | :? Tuple<'a> as t -> Flatten $ (t.Item1)
    | :? Tuple<'a, 'b> as t -> Flatten $ (t.Item1, t.Item2)
    | :? Tuple<'a, 'b, 'c> as t ->Flatten $ (t.Item1, t.Item2, t.Item3)
    | :? Tuple<'a, 'b, 'c, 'd> as t -> Flatten $ (t.Item1, t.Item2, t.Item3, t.Item4)
    | :? Tuple<'a, 'b, 'c, 'd, 'e, 'f> as t -> Flatten $ (t.Item1, t.Item2, t.Item3, t.Item4, t.Item5, t.Item6)
    | :? Tuple<'a, 'b, 'c, 'd, 'e, 'f, 'g> as t -> Flatten $ (t.Item1, t.Item2, t.Item3, t.Item4, t.Item5, t.Item6, t.Item7)
    | :? Tuple<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h> as t -> Flatten $ (t.Item1, t.Item2, t.Item3, t.Item4, t.Item5, t.Item6, t.Item7, t.Item8)
    | _ -> [x]

当然,您需要相应的 static member inline ($)从 1 到 8 的每个参数的实现。这是否解决了您的问题?

附言请注意,我只是将这段代码输入到 Stack Overflow 的答案窗口中;我还没有实际测试过。

关于f# - 如何编写类型安全的递归内联函数来展平元组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43933738/

相关文章:

list - 为什么没有 List.skip 和 List.take?

generics - 为什么显式泛型函数值与类似的非泛型绑定(bind)不同?

javascript - Prestashop - 如何添加内联脚本?

c++ - gcc 中的默认构造内联静态随机数引擎

delphi - Delphi 什么时候尊重 `inline`,什么时候不尊重?

f# - 生命游戏的递归函数不会在异步中运行

f# - 邮箱处理器和异常

c++ - Boost 与 .Net 随机数生成器

html - 内联列表大小问题

android - 在 Flutter 中用不同颜色显示几个单词