在 F# 类型上动态实现静态定义的接口,并在该类型上静态定义函数

问题描述 投票:0回答:1

我有一个看起来类似以下内容的用例:

type Event = | EventA | EventB type IState = abstract member HandleEvent: Event -> IState type ExampleState = { ListOfSomething: int list } interface IState with member this.HandleEvent event = match event with | EventA -> this | EventB -> this let functionThatUsesIState (state: IState) (listOfStates: list<IState>) = state :: listOfStates
使用接口的原因是因为我需要一个包含所有状态的集合,因此,我需要单一类型来使集合同构。在此示例中,为简单起见,我显示了 

list<IState>

。在我的实际应用中,它是一个
Map<string, IState>


我对这种方法的问题是,它要求

functionThatUsesIState

 的用户创建一个类型,然后实现接口。这是
okay-ish,但我更喜欢一种更实用的方法,这样functionThatUsesIState
(或包装它的函数)不采用接口,而是只采用
'T
类型的值,然后是处理 
'T
.
的函数

例如,我可以定义:

,而不是在高层使用接口

type HowIdLikeToDefineState = { ListOfSomething: int list } let howIdLikeToDefineHandleEvent (state: HowIdLikeToDefineState) (event: Event) = match event with | EventA -> state | EventB -> state
如果我这样做的话,这可能会起作用:

let functionThatUsesState (state: 'T) (listOfStates: list<'T>) = state :: listOfStates
这“有效”,但对我的应用程序没有好处。我真正需要的是 

listOfStates

,其中 
'T
 元素之间并不总是(几乎从不)相同。


所以,我想到的一种方法是,如果我可以使用

howIdLikeToDefineHandleEvent

IState
上动态实现
HowIdLikeToDefineState
,那就太好了。

因为这样我就可以做类似的事情:

let highLevelFunctionThatUsesState (state: 'T) (eventHandler: 'T -> Event -> 'T) (listOfStates: list<IState>) = // "dynamically" implement IState on 'T using eventHandler as the implementation of HandleEvent let dynamicIStateBasedOnT = ... // pass this to functionThatUsesIState functionThatUsesIState dynamicIStateBasedOnT listOfStates

似乎在F#中可能是可能的,因为类型扩展对象表达式和反射,但我还没有能够编造出一些东西。我最大的努力是:

let DynamicState = { new IState with member this.HandleEvent event = howIdLikeToDefineHandleEvent this event }
这显然行不通,但传达了这个想法。我不知道如何动态地将接口实现“附加”到现有类型。我什至不知道这是否可能。我也尝试过:

let DynamicState = { new HowIdLikeToDefineState with interface IState with member this.HandleEvent event = howIdLikeToDefineHandleEvent this event }
这也不起作用,因为

new

之后的类型必须是对象表达式的接口。


  1. 我如何解决这个特殊问题,即采用接口、类型和该类型上的函数,然后使用该函数动态实现该类型上的接口,这显然应该与接口的成员定义相匹配?

  2. 我还能如何解决这个问题?我实际上需要一种

    Map<string, State<'T>>

     类型,其中 
    'T
     可以变化。显然这是不可能的,那么我还能如何在 F# 中解决此类问题呢?就我而言,除了一两个与 
    State<'T>
     中的 
    'T
     成员类似的成员之外,
    HandleEvent
     的成员实际上独立于 
    IState

如果 C# 可以在这里做一些有趣的事情,我对此持开放态度,因为我可以将它作为一个库(据说)夹在我的 F# 代码之间。

c# .net interface f# type-constraints
1个回答
0
投票
好吧,这个解决方案只是我想到的。我自己很困惑,所以我不知道这是否是过度紧张,我错过了一些更简单或直接的东西,或者是否有一些愚蠢的原因导致我错过了这个解决方案作为解决此类问题的

the解决方案。

无论哪种方式,这里至少有一个解决方案:

type Event = | EventA | EventB type IState = abstract member HandleEvent: Event -> IState type ExampleState = { ListOfSomething: int list } interface IState with member this.HandleEvent event = match event with | EventA -> this | EventB -> this let functionThatUsesIState (state: IState) (listOfStates: list<IState>) = state :: listOfStates type HowIdLikeToDefineState = { ListOfSomething: int list } let howIdLikeToDefineHandleEvent (state: HowIdLikeToDefineState) (event: Event) = match event with | EventA -> state | EventB -> state /////////////////////////////////////////////////////////////// // Here's where the solution to the question actually starts // // with the full program. // /////////////////////////////////////////////////////////////// type GenericState<'State> = { Value: 'State HandleEvent: 'State -> Event -> 'State } interface IState with member this.HandleEvent event = { this with Value = this.HandleEvent this.Value event } let createGenericState (initialState: 'State) (eventHandler: 'State -> Event -> 'State) : IState = { Value = initialState; HandleEvent = eventHandler } let highLevelFunctionThatUsesState (initialState: 'T) (eventHandler: 'T -> Event -> 'T) (listOfStates: list<IState>) : list<IState> = let genericState = createGenericState initialState eventHandler functionThatUsesIState genericState listOfStates
    
© www.soinside.com 2019 - 2024. All rights reserved.