int - > int list与int - > IEnumerable <'a>类型不兼容

dha*_*ech 4 .net c# linq f#

鉴于:

open System.Linq
Run Code Online (Sandbox Code Playgroud)

这是一个可以接受的表达:

[2; 3; 4].SelectMany(fun n -> { 1..n })
Run Code Online (Sandbox Code Playgroud)

但这不是:

[2; 3; 4].SelectMany(fun n -> [ 1..n ])
Run Code Online (Sandbox Code Playgroud)

错误消息说:

    int -> int list    
is not compatible with type
    int -> System.Collections.Generic.IEnumerable<'a>
Run Code Online (Sandbox Code Playgroud)

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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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

是设计的F#行为还是bug?如果是设计,为什么类似的操作在C#中工作?

Tom*_*cek 9

这是预期的行为.C#通常在类型之间进行比F#更多的自动转换:

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

  • 在F#中,编译器不会自动将结果转换为IEnumerable<T>,因此您的第二个代码段不会键入check - 因为它返回的list<T>是与预期不同的类型IEnumerable<T>(您可以将列表转换为可枚举,但它们是不同的类型).

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

> Seq.collect;;
val it : (('a -> #seq<'c>) -> seq<'a> -> seq<'c>) 
Run Code Online (Sandbox Code Playgroud)

这里,类型#seq<'c>明确表示结果可以是任何可以转换为的类型seq<'c>(这就是#名称中的含义).这就是为什么上一个问题答案有效:

[2; 3; 4] |> Seq.collect (fun n -> [ 1..n ])
Run Code Online (Sandbox Code Playgroud)

  • 啊哈...你对 `#seq&lt;'c&gt;` 中的 `#` 的注释让我读到 [Flexible Types](http://msdn.microsoft.com/en-us/library/dd233198.aspx)在 F# 文档中。我不知道这个注释。谢谢! (2认同)