用于C#的Func和TimeSpan的区分联盟

时间:2016-03-25 20:29:20

标签: lambda f# pattern-matching discriminated-union

我距离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#,所以仍然欢迎破解互操作的解决方案。)

2 个答案:

答案 0 :(得分:3)

在不知道你的意图究竟是什么的情况下很难回答这个问题,所以对你试图解决的问题的定性描述将有助于给出一个明确的答案,我会尽我所能虽然。

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

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

我没有看到您当前的类型定义有任何问题,但使用System.Func编写F#函数非常不寻常。

如果你想要tupled而不是curried参数,你可以这样写:

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

虽然你在学习,但我建议你坚持到第一个,直到你找出差异为止。基本上,curried参数允许方便的部分应用,而tupled参数允许方便地对参数/返回进行分组。有关F#中的currying的详细信息,请参阅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部分活动模式,因为它没有做任何事情。它只需要任何参数并返回Some 1,所以你也可以用通配符替换它。

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

此函数返回一个代数数据类型,如果你给它字符串&#34;它应该返回TimeSpan&#34;它包含1)10秒的时间跨度。作为参数或2)类型DateTime -> DateTime -> Option<DateTime> -> Option<DateTime>的curried函数(最终为任何提供的参数返回DateTime.Now)否则。

答案 1 :(得分:2)

您需要将咖喱结果转换为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)