带接口和linq语句的c#到f#转换

时间:2016-07-20 15:28:02

标签: f# c#-to-f# f#-3.0

我正在尝试将使用接口和Linq的c#方法转换为f#:

public static IEnumerable<ModelEngines> CurrentEngineBuilds(IEnumerable<CurrentModels> thisYearModels, DateTime startRunDate, DateTime endRunDate)
        {
            var engineOptions =
                currentModelYear.SelectMany(c => c.Engines)
                    .Where(e => e.EngineProdStartDate >= startRunDate & e.EngineProdStopDate <= endRunDate);
            return engineOptions;
        }

在上面的方法中,我正在返回一个engineOptions的集合 - 类型是IEnumerable。我正在过滤集合,以便集合中只有具有当前模型年份的特定生产范围的engineOptions。

我在下面有这个粗略的,不起作用的翻译:

let CurrentEngineBuilds : <IEnumerable<ModelEngines>> (thisYearModels : IEnumerable<CurrentModels>) (startRunDate : DateTime) (endRunDate : DateTime) =
    query { 
        for engineOptions in currentModelYear.engineOptions do
        where (engineOptions.EngineProdStartDate >= startRunDate and engineOptions.EngineProdEndDate >= endRunDate )
        select (engineOptions)             
    }
    engineOptions 

这项任务比我预期的要复杂得多。我已经通过一些f#教程来了解基础知识,但它似乎与接口和/或linq有关,这很难。

我遇到的一些问题:

  • 你如何使用f#中的接口?
  • 是否存在SelectMany方法的f#equivilent?

有关如何进行c#到f#转换的任何提示?

3 个答案:

答案 0 :(得分:4)

IEnumerable<'T>在F#中被命名为seq<'T>。在这种情况下,我没有看到任何使用LINQ query表达式的理由;更惯用的F#翻译将使用the Seq module

let CurrentEngineBuilds thisYearModels startRunDate endRunDate =
    thisYearModels
    //     v--- SelectMany
    |> Seq.collect (fun c -> c.Engines)
    //     v--- Where
    |> Seq.filter (fun e ->
        e.EngineProdStartDate >= startRunDate && e.EngineProdStopDate <= endRunDate)

如果thisYearModels的类型未自动推断,您可以在函数签名中对其进行注释:

let CurrentEngineBuilds (thisYearModels:seq<CurrentModels>) startRunDate endRunDate = ...

或身体:

let CurrentEngineBuilds thisYearModels startRunDate endRunDate =
    (thisYearModels:seq<CurrentModels>)
    |> Seq.collect (fun c -> c.Engines)
    |> Seq.filter (fun e ->
        e.EngineProdStartDate >= startRunDate && e.EngineProdStopDate <= endRunDate)
// or
let CurrentEngineBuilds thisYearModels startRunDate endRunDate =
    thisYearModels
    |> Seq.collect (fun (c:CurrentModels) -> c.Engines)
    |> Seq.filter (fun e ->
        e.EngineProdStartDate >= startRunDate && e.EngineProdStopDate <= endRunDate)

答案 1 :(得分:3)

您实际上可以在F#中使用LINQ而不会出现任何问题。这是您原始示例的几乎直接端口(我假设currentModelYear是一种类型,您的意思是thisYearModels

open System.Linq
let currentEngineBuilds(thisYearModels:seq<CurrentModels>, startRunDate, endRunDate) =
    let engineOptions =
        thisYearModels
            .SelectMany(fun e -> e.Engines)
            .Where(fun e -> e.StartDate >= startRunDate && e.StopDate <= endRunDate)
    engineOptions // return keyword not required

出于本文的目的,您可以将seq<T>视为IEnumerable<T>的简写。

话虽如此,我认为您会发现Seq模块更适合F#,因为它旨在利用F#语言功能,例如Tuples,并且可以提供帮助类型推断过程。

答案 2 :(得分:2)

|>或&#34;管道&#34; operator是F#将函数应用于值的惯用方法。

v |> f与之前指出的f v相同。

另一方面,Monadic链接完全是另一回事。您在原始帖子中的query计算表达式中使用了monadic链接,并且也是惯用语。

希望有助于将这两个(相当复杂的)概念与您的理解区分开来! :)