2015-11-17 5 views
2

Я пытаюсь реализовать универсальную функцию, которая вызывает член типа. Я обнаружил, что это должно быть возможно, используя inline. Это не помогло, поэтому я попытался реализовать интерфейс, например:Обертка для члена типа

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 

Это работает очень хорошо, давая выход типа

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 

я нахожу этот способ быть очень некрасиво, хотя , Мой вопрос: есть ли лучший способ обернуть член в функцию?

+1

вы, вероятно, ищете [статический разрешенные параметры типа] (https://msdn.microsoft.com/en-us/library/dd548046.aspx) (вы можете сделать довольно впечатляющие вещи с теми) - I просто интересно, что вы пытаетесь сделать здесь - это просто выбор правильного 'wrap' по типу' o'? – Carsten

+0

Что вы подразумеваете под * wrapping членом в функции? * Единственный член, присутствующий здесь, - это 'Wrap', который (IIUC) вы внедрили для достижения своей цели ... Итак, основной вопрос заключается в том, : Какова ваша цель? –

+0

@MarkSeemann Это все о том, как заставить функцию 'wrap' работать с каждым типом, который имеет член' Wrap'. – seequ

ответ

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, потому что я не знаю вашего Scene и Cash и хотите проверить:

> 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") 
+0

Действительно, в то время как синтаксис немного удручен в моих глазах, я думаю, что он по-прежнему гораздо приятнее, чем обманывать интерфейсы. Спасибо. – seequ

+0

Да, синтаксис противный - в основном я должен использовать 2-3 WTF каждый раз, когда я пытаюсь это сделать (это '(o, f)' или '(of)'? ... было ли это '(member ...) (o) 'или' (член ... (o)) 'и т. д. pp) – Carsten

1

Почему бы не использовать оператора? неявно разрешенный символический оператор будет скомпилирован как статическое выражение вызова ограничения числа в любом случае без уродливого синтаксиса. Эта языковая функция зависит от статически разрешенных параметров типа. См. 14.2.2 (последняя строка) F# spec.

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) 
+0

Мне не удобно добавлять ненужные операторы, особенно если функция не должна использоваться с двумя аргументами обычно. – seequ