c# - int -> int 列表与类型 int -> IEnumerable<'a> 不兼容

标签 c# .net linq f#

给定:

open System.Linq

这是一个可接受的表达方式:

[2; 3; 4].SelectMany(fun n -> { 1..n })

然而这不是:

[2; 3; 4].SelectMany(fun n -> [ 1..n ])

错误信息是这样的:

    int -> int list    
is not compatible with type
    int -> System.Collections.Generic.IEnumerable<'a>

F# 正在拒绝该表达式,因为该函数正在返回 int list .

考虑这个执行类似操作的 C# 程序:

using System;
using System.Collections.Generic;
using System.Linq;

namespace SelectManyCs
{
    class Program
    {
        static List<int> Iota(int n)
        {
            var ls = new List<int>();

            for (var i = 0; i < n; i++) ls.Add(i);

            return ls;
        }

        static void Main(string[] args)
        {
            var seq = new List<int>() { 2, 3, 4 };

            foreach (var elt in seq.SelectMany(Iota))
                Console.WriteLine(elt);
        }
    }
}

Iota返回 List<int>并将其传递给 SelectMany C# 可以接受。

F# 行为是设计使然还是错误?如果是设计使然,为什么类似的操作在 C# 中有效?

最佳答案

这是预期的行为。 C# 通常比 F# 做更多类型间的自动转换:

  • 在 C# 中,lambda 函数的结果是 List<T> , 但 C# 编译器会自动将结果转换为 IEnumerable<T> ,这是函数的预期返回类型。

  • 在 F# 中,编译器不会自动将结果转换为 IEnumerable<T>所以你的第二个片段没有输入检查 - 因为它正在返回 list<T>这与预期的类型不同 IEnumerable<T> (您可以将列表转换为可枚举的,但它们是不同的类型)。

F# 库定义了自己的 SelectMany 版本操作称为 Seq.collect . F# 函数具有以下类型:

> Seq.collect;;
val it : (('a -> #seq<'c>) -> seq<'a> -> seq<'c>) 

在这里,输入 #seq<'c>明确表示结果可以是任何可以转换为 seq<'c> 的类型(这就是名称中的 # 的意思)。这就是为什么 answer to your previous question作品:

[2; 3; 4] |> Seq.collect (fun n -> [ 1..n ])

关于c# - int -> int 列表与类型 int -> IEnumerable<'a> 不兼容,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23316324/

相关文章:

c# - 错误 :The preLaunchTask 'build' terminated with exit code 1

c# - 将 .NET 结构与 WINAPI 函数结合使用

c# - 如何使用 Dynamic LINQ 求和

c# - linq查询返回唯一项的嵌套列表

c# - 我需要把.xlsx下载

java - 在数据库上更改表格后,如何自动更改 Windows 应用程序中的网格?

c# - 用于 asp.net 的导出到 Excel 工具

java - Java 包是否等同于 .Net 程序集?

.net - .Net 中的舍入差异

c# - 使用 Linq 在两个嵌套 List<T> 中透视数据