【问题标题】:How to construct F# tuple type?如何构造 F# 元组类型?
【发布时间】:2015-07-15 16:16:26
【问题描述】:

给定 F# 中的以下类型

type Message = string * AsyncReplyChannel<SymbolicExpression>

我该如何构建它? F# for fun and profit 的好东西,但我找不到如何构造新的“代数数据类型”Message

这是我想要做的:

member x.Evaluate(expression: string, ?timeout) : SymbolicExpression =        
    agent.PostAndReply(fun c -> Message (expression,c), ?timeout=timeout) 

我正在尝试将MailboxProcessor 公开给 C#,并尝试使尽可能多的 F# 特定类型远离 C# 代码。因此,我试图只接受一个字符串并返回一个 SymbolicExpression 类型(来自 RDotNet 命名空间)。

更新

好的 - 这是完整的来源。

open RDotNet

type Message = string * AsyncReplyChannel<SymbolicExpression>

type RInterfaceAgent(dllpath:string, rhome:string) =
    let engine = 
        RDotNet.REngine.SetEnvironmentVariables(dllpath,rhome)
        RDotNet.REngine.GetInstance()

    let agent = MailboxProcessor<Message>.Start(fun inbox ->
        let rec messageLoop n = async {
            let! (msg, channel) = inbox.Receive()
            engine.Evaluate(msg) |> channel.Reply
            do! messageLoop (n+1)
        }
        messageLoop 0
    )      

    member x.Evaluate(ex: string, ?timeout) : SymbolicExpression =        
        agent.PostAndReply((fun c -> Message (ex, c)), ?timeout=timeout)

这部分的错误信息:(fun c -&gt; Message (ex, c))是:

未定义值或构造函数消息

【问题讨论】:

  • 嗨@ildjarn - 谢谢,但不起作用。该类型没有构造函数 - 这是我的问题。我正在寻找一种解决方案来添加它,或者不添加它,或者以防我做一些愚蠢的事情 - 做其他事情。
  • 您的 Message 是元组的别名,因此您可以自己传递元组或将类型 Message 更改为 DU,例如type Message = | Message of string * AsyncReplyChannel&lt;SymbolicExpression&gt;
  • 为什么你的错误信息显示expression而不是ex
  • @Guvante 因为我重构了
  • @spike:您有一个名为ex 的参数,并且您在屏幕截图中传入了expression

标签: f# c#-to-f# r.net


【解决方案1】:

您定义它的方式,Message 只是Tuple&lt;String, AsyncReplyChannel&lt;SymbolicExpression&gt;&gt; 的别名,因此它没有显式构造函数,指定对的任何元组都是消息。你可以只返回一个(expression,c),而不是Message (expression,c)

您正在寻找的可能是使其成为记录类型:

类型消息 = {str:字符串;表达式:AsyncReplyChannel }

然后你只能通过显式命名字段来构造它

{str=... ;表达式 = ... }

【讨论】:

  • 谢谢 - 但这不起作用。我认为它需要一个Message 的实例(见附图)
  • 嘿——事实证明你是对的。不知道我第一次尝试时发生了什么。谢谢!
【解决方案2】:

您的消息定义只是元组的类型别名。编译器将这些类型视为等价的 - 因此您有时可以在工具提示中看到 Message,有时还可以看到扩展定义。

type Message = string * AsyncReplyChannel<SymbolicExpression>

假设这是类型并且agentMailboxProcessor&lt;Message&gt; 类型,那么将其发送给代理的以下方式应该有效:

member x.Evaluate(ex: string, ?timeout) : SymbolicExpression =        
    agent.PostAndReply((fun c -> (ex, c)), ?timeout=timeout)

(ex, c) 位只是创建一个元组(Message 就是这样)。 请注意,您需要将 lambda 函数括在括号中(屏幕截图中缺少该括号)。

另外,不幸的是,F# 和 C# 中的可选参数的工作方式不同。因此,如果您正在编写 C# 友好的 API,则需要使用 C# 样式的可选参数,大致如下所示:

open System.Runtime.InteropServices

member x.Evaluate(ex:string, [<Optional>]timeout:Nullable<int>) = 
  let timeout = if timeout.HasValue then Some(timeout.Value) else None
  (...)

【讨论】:

  • 谢谢 - 非常有帮助!我最近在 C#/F# 上阅读了 很多 我们的资料——例如关于逆变换和协变。
猜你喜欢
  • 2014-03-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-06-18
  • 2022-12-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多