2016-02-12 59 views
1

我是F#和函数式编程的新手,需要一些帮助。我来自C#,所以我的思维方式仍然有点不同。如何将记录的属性声明为抽象函数

我需要将某些选项传递给一个函数,我正在使用这个记录。其中一个选项是延续功能单元 - >选件<'a>。我无法弄清楚如何定义记录类型。下面是我一直在尝试的一个例子。

type Func2<'a> = 'a -> 'a option 

type ProcessOptions = { 
     func1: int -> int option 
     func2: Func2<int> // This works... 
     //func2: Func2<'a> // ... but this is what I'm trying to achieve - so that I can pass any Func2<'a> using this record. 
    } 

let f1 a = 
    let r = Some a 
    printfn "f1: %A" r |> ignore 
    r 

let f2 (a:'a) = 
    let r = Some a 
    printfn "f2: %A" r |> ignore 
    r 

let f3 (processOptions:ProcessOptions) = 
    processOptions.func1(3) |> ignore 
    processOptions.func2 789 |> ignore 
    () 

let f4 (processOptions:ProcessOptions) = 
    processOptions.func1(4) |> ignore 
    //processOptions.func2 "abc" |> ignore // as a result this does not work... 
    () 

[<EntryPoint>] 
let main argv = 

    f1(1) |> ignore 
    f2 123 |> ignore 
    f2 "abc" |> ignore 

    let fo = { 
     func1 = f1 
     func2 = f2 
    } 
    f3 fo 

    let fo1 = { 
     func1 = f1 
     func2 = f2 
    } 
    f4 fo1 


    0 

回答

1

记录内部的成员不能是通用功能(你可以用不同类型的参数,例如int或致电string)。它将始终有一个固定类型。

你可以使用一个技巧是定义一个简单的界面与通用方法:

type Func = 
    abstract Invoke<'a> : 'a -> 'a option 

现在在记录你的会员可以只是Func型(不带泛型类型参数),但Invoke里面Func方法是通用的:

type ProcessOptions = 
     { func1: Func 
     func2: Func } 

创建Func值比写普通函数难一点,但您可以使用对象的表达式:

let f1 = 
    { new Func2 with 
     member x.Invoke(a) = 
     let r = Some a 
     printfn "f1: %A" r |> ignore 
     r } 

,您现在可以绕过ProcessOptions并调用Invoke方法与不同类型的参数:

let f4 (processOptions:ProcessOptions) = 
    processOptions.func1.Invoke 4 |> ignore 
    processOptions.func2.Invoke "abc" |> ignore 

f4 { func1 = f1; func2 = f1 } 
+0

感谢托马斯。我喜欢你的解决方案,因为它可以方便地将其他功能类型添加到记录中。 John的解决方案也可行,但我想我必须为ProcessOptions <...>添加更多的通用类型以获取其他通用类型。 –

1

在这里,您需要做的记录一般 - 与服用点状

type ProcessOptions<'a> = { 
     func1: int -> int option 

     func2: Func2<'a> // ... but this is what I'm trying to achieve - so that I can pass any Func2<'a> using this record. 
    }