我正在与Akkling一起在F#中工作,因此我可以在Akka.net上使用强类型演员,但是我遇到了F#中的设计限制,我想知道是否有解决此问题的优雅方法。
采用我的根消息类型,我真的不想要IActorRef <_>放在其中,因为该类型将存在于公共库中,并且不应该知道它使用的消息系统。另外,为了方便测试,我不需要创建整个actor系统(或测试套件)。
type MessageType =
| World of WorldMessage
| Location of IActorRef<LocationMessage> * LocationMessage
| Client of IActorRef<LocationMessage> * ClientMessage
这是一个可怕的解决方法:
type MessageType<'LocationActor, 'PlayerActor, 'ClientActor> =
| World of WorldMessage<'ClientActor>
| Location of 'LocationActor * LocationMessage<'ClientActor>
| Client of 'ClientActor * ClientMessage<'LocationActor>
理想情况下,我想这样做,但是存在语言限制(错误:类型参数不能用作类型构造函数):
type MessageType<'a> =
| World of WorldMessage<'a>
| Location of 'a<LocationMessage> * LocationMessage
| Client of 'a<LocationMessage> * ClientMessage
答案 0 :(得分:5)
实际的类型系统问题已在注释中提到(缺少HKT),但我认为在这里解决设计问题并不是真正必要的。
您不希望直接依赖Akka.NET,但是您仍然希望您的类型带有一个将actor引用与消息一起使用的概念。一种解决方法是在Actor周围引入自己的接口(作为实际的接口类型或一组函数,具体取决于您所处的环境)。
因此,在您的公共库中,您拥有自己的IMyActorRef
,并拥有您认为IActorRef
功能的合理公共子集:
type IMyActorRef<'msg> =
abstract member Tell: ... -> ...
abstract member Ask: ... -> ...
并根据该接口定义消息类型(以及使用该消息的实际逻辑):
type MessageType =
| World of WorldMessage
| Location of IMyActorRef<LocationMessage> * LocationMessage
| Client of IMyActorRef<ClientMessage> * ClientMessage
然后在您引用Akka.NET时为其提供实现。