F#-类型参数不能用作类型构造函数

时间:2018-06-20 09:17:57

标签: f# akka.net

我正在与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

1 个答案:

答案 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时为其提供实现。