如何在F#中申请?

rob*_*kuz 5 generics f#

给出以下类型和成员函数

type Result<'TSuccess, 'TError> = 
    | Success of 'TSuccess 
    | Error of 'TError list
    with 
    member this.apply fn =
        match (fn, this) with
        | Success(f), Success(x) -> Success(f x)
        | Error(e), Success(_) -> Error(e)
        | Success(_), Error(e) -> Error(e)
        | Error(e1), Error(e2) -> Error(List.concat [e1;e2])
Run Code Online (Sandbox Code Playgroud)

以及内联函数

let inline (<*>) (f: ^A) (t:^A) = 
    let apply' = (^A : (member apply : ^A -> ^A) (t, f))
    apply'
Run Code Online (Sandbox Code Playgroud)

而这个电话网站

let y () = Success (fun x -> x + 1) <*> (Success 3)
Run Code Online (Sandbox Code Playgroud)

我收到以下错误

 let y () = Success (fun x -> x + 1) <*> (Success 3);;
 -----------^^^^^^^^^^^^^^^^^^^^^^^^
 /Users/robkuz/stdin(473,12): error FS0001: Type constraint mismatch. 
The type
   Result<'a,'c>
is not compatible with type
   Result<('a -> 'b),'c>
The resulting type would be infinite when unifying ''a' and ''a -> 'b'
Run Code Online (Sandbox Code Playgroud)

这一切都是试图模仿Haskells Applicative并且签名应该是

(<*>) :: forall f a b. Apply f => f (a -> b) -> f a -> f b
Run Code Online (Sandbox Code Playgroud)

但我不认为在F#中无法表达这一点

有关如何实现这一目标的任何想法?

Tom*_*cek 7

一般来说,我认为尝试在F#中模拟Haskell模式并不是一个好主意.在Haskell中,很多代码都是非常通用的,因为monad和applicatives的使用频率更高.

在F#中,我更喜欢编写更专业的代码,因为你不需要在monad或applicatives上编写代码多态,它只是让你更容易看到发生了什么.所以,我认为我不想<*>在F#中编写适用于任何"应用"的运算符.

也就是说,代码的问题在于<*>运算符^A对两个参数和结果使用相同的类型参数(虽然它们在调用中是不同的类型) - 如果使用三个单独的类型参数,它可以正常工作:

let inline (<*>) (f: ^B) (t:^A) : ^C = 
    let apply' = (^A : (member apply : ^B -> ^C) (t, f))
    apply'
Run Code Online (Sandbox Code Playgroud)