在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#,并试图保留与C#代码不同的F#特定类型。因此,我尝试仅接受一个字符串并重新设置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 -> Message (ex, c))
是:
未定义值或构造函数消息
答案 0 :(得分:4)
您定义它的方式,Message
只是Tuple<String, AsyncReplyChannel<SymbolicExpression>>
的别名,因此它没有显式构造函数,指定对的任何元组都是Message。您只需返回(expression,c)
,而不是Message (expression,c)
您正在寻找的可能是它的记录类型:
type Message = {str:String;表达式:AsyncReplyChannel&lt; SymbolicExpression&gt; }
然后你只能通过明确命名字段
来构建它{str = ...; expression = ...}
答案 1 :(得分:3)
您的消息定义只是元组的类型别名。编译器将类型视为等效类型 - 因此您有时可以在工具提示中看到Message
,有时也可以看到扩展的定义。
type Message = string * AsyncReplyChannel<SymbolicExpression>
假设这是类型且agent
属于MailboxProcessor<Message>
类型,以下将其发送给代理的方式应该有效:
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
(...)