首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何为扁平的元组编写类型can递归内联函数?

如何为扁平的元组编写类型can递归内联函数?
EN

Stack Overflow用户
提问于 2017-05-12 09:08:33
回答 2查看 387关注 0票数 2

我想要创建一个类型安全的递归函数,以使元组变平。但是,就类型安全性而言,我不能低于第一个递归级别。

代码语言:javascript
运行
复制
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

我尝试了另一种方法

代码语言:javascript
运行
复制
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))

但我不能让那个人打字检查。

有人有线索吗?

一个附加需求

我这么做的部分原因是我想

代码语言:javascript
运行
复制
let a1 = flatten (1, (2, 2, 3), (3,3))

屈服

代码语言:javascript
运行
复制
val a1 : int list

这是因为当我输入一个int元组的元组时,唯一合理的结果应该是一个int list。目前,我得到一个obj list int,第一个示例是第二个编译错误。

诚挚的问候

EN

回答 2

Stack Overflow用户

发布于 2017-05-12 09:42:43

.Net Tuple类的类型参数数为从1到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>>的元组。

然而,您的第一种方法只处理flatten (1, (2, 2, 3, 4), (3,3)) 2和3,但是当您执行时,您正在使用一个4元组来测试它。如果您按照以下方式重写第一个Flat函数会怎么样?

代码语言:javascript
运行
复制
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]

当然,您还需要从1到8之间的每个位置都需要相应的static member inline ($)实现。这样可以解决问题吗?

请注意,我只是在Stack溢出的应答窗口中输入了这段代码;我还没有真正测试它。

票数 4
EN

Stack Overflow用户

发布于 2017-05-12 21:15:05

我想打赌,如果没有运行时类型测试,这是不可能以类型安全的方式完成的。

代码语言:javascript
运行
复制
module Tuple =
    open Microsoft.FSharp.Reflection
    let rec collect<'T> (x : obj) = [|
        if FSharpType.IsTuple <| x.GetType() then
            for y in FSharpValue.GetTupleFields x do
                yield! collect y 
        elif x :? 'T then yield x :?> 'T |]

Tuple.collect<int> (((100,101,102),"X"),1,2,3,(4,5))
// val it : int [] = [|100; 101; 102; 1; 2; 3; 4; 5|]

内联重载解析不起作用,因为F#的类型系统不足以通过成员约束区分类型'T和元组'T*'T;元组必须被视为原子单元'T。因此,编译时场景将始终解析为原子情况,而不是元组。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/43933738

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档