使用接口和 linq 语句将 c# 转换为 f#
c# to f# conversion with interfaces and linq statements
我正在尝试将这个使用接口和 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# 教程来了解基础知识,但似乎与接口有关 and/or linq 非常困难。
我遇到的一些问题:
- 你到底是怎么在 f# 中使用接口的?
- 是否有与 SelectMany 方法等效的 f#?
关于如何将 c# 转换为 f# 的任何提示?
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)
您实际上可以在 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
出于此 post 的目的,您可以将 seq<T>
视为 IEnumerable<T>
的 shorthand。
话虽如此,我认为您会发现 Seq
模块更适合 F#,因为它旨在利用 F# 语言功能(例如元组),并且可以协助类型推断过程.
|>
或 "pipe" 运算符是 F# 将函数应用于值的惯用方式。
v |> f
与前面指出的 f v
相同。
另一方面,Monadic 链接完全是另一回事。您在原始 post 的 query
计算表达式中使用了单子链接,它是 也 惯用的。
希望这有助于在您的理解中区分这两个(相当复杂的)概念! :)
我正在尝试将这个使用接口和 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# 教程来了解基础知识,但似乎与接口有关 and/or linq 非常困难。
我遇到的一些问题:
- 你到底是怎么在 f# 中使用接口的?
- 是否有与 SelectMany 方法等效的 f#?
关于如何将 c# 转换为 f# 的任何提示?
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)
您实际上可以在 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
出于此 post 的目的,您可以将 seq<T>
视为 IEnumerable<T>
的 shorthand。
话虽如此,我认为您会发现 Seq
模块更适合 F#,因为它旨在利用 F# 语言功能(例如元组),并且可以协助类型推断过程.
|>
或 "pipe" 运算符是 F# 将函数应用于值的惯用方式。
v |> f
与前面指出的 f v
相同。
另一方面,Monadic 链接完全是另一回事。您在原始 post 的 query
计算表达式中使用了单子链接,它是 也 惯用的。
希望这有助于在您的理解中区分这两个(相当复杂的)概念! :)