【问题标题】:How to flatten input of mixed 'T and seq<'T> into single seq<'T>如何将混合 'T 和 seq<'T> 的输入展平为单个 seq<'T>
【发布时间】:2013-11-24 02:44:14
【问题描述】:

我需要一个可以接受任意数量参数的函数,每个参数可以是'T 或seq&lt;'T&gt; 类型。在函数内部,我需要将其作为单个 seq&lt;'T&gt; 进行处理,所有输入的组合顺序与它们提供的顺序相同。

显而易见的方法是:

module Test =
    let flatten ([<ParamArray>] args) =
        let flat = seq {
                for a in args do
                    match box a with
                    | :? int as x -> yield x
                    | :? seq<int> as sq -> 
                        for s in sq do
                            yield s
                    | _ -> failwith "wrong input type"
                }
        flat // this should be seq<int>

但即使是最简单的情况,我也无法让它在 FSI 中工作

let fl = Test.flatten 1;;
  ----------------------^

...: error FS0001: The type 'int' is not compatible with the type 'seq<'a>'

这里出了什么问题以及如何根据需要使其工作?或许这可以通过一些完全不同的方式来完成?

【问题讨论】:

    标签: f# f#-interactive


    【解决方案1】:

    来自msdn:

    在 F# 中,参数数组只能在方法中定义。他们不能 用于独立函数或定义在 模块。

    因此,不要使用模块,而是使用静态方法声明类型。

    open System
    type Test() =
        static member flatten ([<ParamArray>] args: obj[]) =
            let flat = seq {
                    for a in args do
                        match box a with
                        | :? int as x -> yield x
                        | :? seq<int> as sq -> 
                            for s in sq do
                                yield s
                        | _ -> failwith "wrong input type"
                    }
            flat
    

    如果您有其他 let 绑定,您仍然可以声明具有相同名称的模块。 另请注意,在比赛的第二个后卫中,您可以通过以下方式避免 for 循环:

    | :? seq<int> as sq -> yield! sq 
    

    并且box 不是必需的。

    【讨论】:

    • 最近在stackoverflow.com/a/674422/801189讨论了这个,其实一个模块可以有这样的功能,只有let in表达式不能。我仍然无法让它在 FSI 中工作。你试过在 FSI 中运行它吗?
    • 是的,它运行良好。将代码复制到 .fsx 中,发送到 fsi 并在 fsi 中尝试 let fl = Test.flatten(1,seq [1;2;3])
    • 谢谢!看起来 MSDN 是对的(我在链接的讨论中是对的)。现在它可以工作了,但我仍然更喜欢模块,而不是类型。
    • 我个人不在乎是否必须将其放入类型中,从外部世界是相同的并且模块被编译为类型。当我编写打算从 C# 中使用的函数时,我通常会使用类型,因此我可以使用更多的 .NET 特性,如此类或重载。
    • 好的,在这种情况下,而不是 ParamArray,我将只使用一个接受列表的函数。所以我将调用 funA [funB [x]; funC [y]]
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-20
    • 1970-01-01
    • 1970-01-01
    • 2011-12-26
    相关资源
    最近更新 更多