Wrapper for a type member

时间:2015-11-17 15:46:09

标签: generics f# wrapper

I've been trying to implement a generic function that calls a member of a type. I found that this should be possible by using inline. It didn't help, so I attempted to implement an interface, like this:

type Wrappable<'a, 'b> =
    interface
      abstract Wrap : ('b -> 'b) -> 'a
    end

type StateType =
    State of Scene * Cash | Exit
    interface Wrappable<StateType, Scene * Cash> with
        member this.Wrap f =
            match this with
            | Exit -> Exit
            | State (scene, cash) -> f (scene, cash) |> State

let inline wrap f (o:Wrappable<_, _>) = o.Wrap f

This works very well, giving the type output

type Wrappable<'a,'b> =
  interface
    abstract member Wrap : ('b -> 'b) -> 'a
  end
type StateType =
  | State of Scene * Cash
  | Exit
  with
    interface Wrappable<StateType,(Scene * Cash)>
  end
val inline wrap : f:('a -> 'a) -> o:Wrappable<'b,'a> -> 'b

I find this way to be very ugly, though. My question is: is there a better way to wrap a member in a function?

2 个答案:

答案 0 :(得分:5)

这是你如何使用我提到的statically resolved type parameters来完成的:

type StateType =
    State of int * string | Exit
        member this.Wrap f =
            match this with
            | Exit -> Exit
            | State (scene, cash) -> f (scene, cash) |> State

let inline wrap f (o : ^a) = (^a : (member Wrap : (^b -> ^b) -> ^a) (o, f))

我使用了int * string,因为我不知道您的SceneCash并且想要测试它:

> let x = State (5,"Hallo");;

val x : StateType = State (5,"Hallo")

> let f (x,y) = (x+x,y);;

val f : x:int * y:'a -> int * 'a

> wrap f x;;

val it : StateType = State (10,"Hallo")

答案 1 :(得分:1)

为什么不使用运营商?无论如何,隐式解析的符号运算符将被编译为静态成员约束调用表达式,而不会出现难看的语法。该语言功能依赖于静态解析的类型参数。见F# spec的第14.2.2节(最后一行)。

type StateType =
    State of int * string | Exit
    static member ($) (this, f) =
        match this with
        | Exit -> Exit
        | State (scene, cash) -> f (scene, cash) |> State

type UnitType =
    | Etats of float * unit
    static member ($) (Etats (scene, ()), f) =
        f (scene, ()) |> Etats

let inline f (x,y) = (x+x,y)

let st = State (5,"Hallo")
st $ f   // val it : StateType = State (10,"Hallo")

let ut = Etats (5., ())
ut $ f   // val it : UnitType = Etats (10.0,null)