C# 的 Func 和 TimeSpan 的可区分联合

Discriminated Union of Func and TimeSpan for C#

我刚接触 F# 大约 2 小时,在弄清楚如何声明可以是 Func<DateTime, DateTime, Option<DateTime>, Option<DateTime>>TimeSpan.

的可区分联合类型时遇到了一些问题
namespace Test

open System

type FuncOrTimeSpan = 
  // Should this be written in a different way to be able to take fun (a, b, c) -> ...?
  | Func of Func<DateTime, DateTime, Option<DateTime>, Option<DateTime>>
  | TimeSpan of TimeSpan

module ThingDoer

  let (|ActiveThing|_|) input = Option.Some(1)

  // Do I need to tell this function that I expect it to return FuncOrTimeSpan?
  let ReturnEitherFuncOrTimeSpan input =
    match input with
    | "should return TimeSpan" -> FuncOrTimeSpan.TimeSpan(TimeSpan.FromSeconds(10))
    | ActiveThing number -> FuncOrTimeSpan.Func(fun (a, b, c) -> Option.Some(DateTime.Now))

我因为以下原因而大喊大叫:这个函数接受了太多的参数,或者在不需要函数的上下文中使用。

我该怎么做才能将 lambda 传递给 FuncOrTimeSpan.Func

此外,我是否应该将 Func of Func<DateTime, DateTime, Option<DateTime> 重写为 Func of DateTime -> DateTime -> Option<DateTime> -> Option<DateTime> 之类的东西?我不知道这意味着什么,我试过也没用。

我可能应该注意到,我计划从 C# 连接这个函数(但也许应该连接它的 C# 部分也将重写为 F#,因此仍然欢迎打破互操作的解决方案)。

您需要将 curry 结果转换为 System.Func

  let ReturnEitherFuncOrTimeSpan input =
    match input with
    | "should return TimeSpan" ->
        let timespan =  TimeSpan.FromSeconds(10.0)
        FuncOrTimeSpan.TimeSpan(timespan)
    | ActiveThing number -> 
            let curryResult = fun (a : DateTime) (b:DateTime) (c:DateTime option) -> Some(DateTime.Now)
            let funcResult = System.Func<_,_,_,_>(curryResult) 
            FuncOrTimeSpan.Func(funcResult)

如果不知道你的意图到底是什么,很难回答这个问题,所以对你试图解决的问题进行定性描述将有助于给出明确的答案,不过我会尽力而为。

首先,您的类型定义应该如下所示:

type FuncOrTimeSpan = 
    | Func of (DateTime -> DateTime -> Option<DateTime> -> Option<DateTime>)
    | TimeSpan of TimeSpan

我没有发现您当前的类型定义有任何问题,但是使用 System.Func.

编写 F# 函数非常不寻常

如果你想要元组参数而不是柯里化参数,你可以这样写:

type FuncOrTimeSpan = 
    | Func of (DateTime * DateTime * Option<DateTime> -> Option<DateTime>)
    | TimeSpan of TimeSpan

虽然您正在学习,但我建议您坚持第一个,直到您找出差异。基本上,柯里化参数允许方便的部分应用,而元组参数允许方便地分组 parameters/returns。有关 F# 中柯里化的更多详细信息,请参阅 https://fsharpforfunandprofit.com/posts/currying/

无论如何,继续第一个类型定义,您的函数将如下所示:

let returnEitherFuncOrTimeSpan input =
    match input with
    | "should return TimeSpan" -> TimeSpan(TimeSpan.FromSeconds(10.0))
    | ActiveThing number -> Func(fun a b c -> Some(DateTime.Now))

我不知道您为什么要使用这个 ActiveThing 部分活动模式,因为它什么都不做。它只需要任何参数和 returns Some 1 所以你不妨用通配符替换它。

let returnEitherFuncOrTimeSpan input =
    match input with
    | "should return TimeSpan" -> TimeSpan(TimeSpan.FromSeconds(10.0))
    | _ -> Func(fun a b c -> Some(DateTime.Now))

此函数 returns 一种代数数据类型,包含 1) 10 秒的时间跨度(如果您将字符串 "should return TimeSpan" 作为参数)或 2) 类型为 [=17 的柯里化函数=](最终 returns DateTime.Now 对于任何提供的参数)否则。