我正在使用Akkling在F#工作,所以我可以使用Akka.net上的强类型演员,但是我在F#中遇到了设计限制,我想知道是否有一种优雅的方式.
拿我的根消息类型,我真的不想在那里有IActorRef <_>,因为这种类型将存在于一个公共库中,并且不应该知道它使用的消息系统.此外,为了便于测试,我不想创建整个actor系统(或测试工具包).
type MessageType =
| World of WorldMessage
| Location of IActorRef<LocationMessage> * LocationMessage
| Client of IActorRef<LocationMessage> * ClientMessage
Run Code Online (Sandbox Code Playgroud)
一个可怕的工作是:
type MessageType<'LocationActor, 'PlayerActor, 'ClientActor> =
| World of WorldMessage<'ClientActor>
| Location of 'LocationActor * LocationMessage<'ClientActor>
| Client of 'ClientActor * ClientMessage<'LocationActor>
Run Code Online (Sandbox Code Playgroud)
理想情况下,我想这样但有一个语言限制(错误:类型参数不能用作类型构造函数):
type MessageType<'a> =
| World of WorldMessage<'a>
| Location of 'a<LocationMessage> * LocationMessage
| Client of 'a<LocationMessage> * ClientMessage
Run Code Online (Sandbox Code Playgroud)
实际的类型系统问题已经在评论中提到(缺少HKT),但我不认为他们真的有必要在这里解决设计问题.
您不希望直接依赖于Akka.NET,但是您仍然希望您的类型带有一个带有actor引用的概念.一种方法是在Actors周围引入您自己的界面(作为实际的接口类型或一组函数,取决于您的上下文中有意义的).
因此,在您的公共库中,您可以使用自己IMyActorRef认为合理的常用IActorRef功能子集:
type IMyActorRef<'msg> =
abstract member Tell: ... -> ...
abstract member Ask: ... -> ...
Run Code Online (Sandbox Code Playgroud)
并根据该接口定义您的消息类型(以及消耗它的实际逻辑):
type MessageType =
| World of WorldMessage
| Location of IMyActorRef<LocationMessage> * LocationMessage
| Client of IMyActorRef<ClientMessage> * ClientMessage
Run Code Online (Sandbox Code Playgroud)
然后在您引用Akka.NET时提供它的实现.