How to do a Applicative in F#?

我只是一个虾纸丫 提交于 2019-12-10 13:56:43

问题


Given the following type and member function

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])

and the following inline function

let inline (<*>) (f: ^A) (t:^A) = 
    let apply' = (^A : (member apply : ^A -> ^A) (t, f))
    apply'

And this call site

let y () = Success (fun x -> x + 1) <*> (Success 3)

I get the following error

 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'

This whole thing is an attempt to emulate Haskells Applicative and the signature should be

(<*>) :: forall f a b. Apply f => f (a -> b) -> f a -> f b

But I dont afaik there is no way to express that in F#

Any ideas on how to make that happen?


回答1:


In general, I think it is not a good idea to try to emulate Haskell patterns in F#. In Haskell, lot of code is written as very generic, because monads and applicatives are used more frequently.

In F#, I prefer writing more specialized code, because you do not need to write code polymorphic over monads or applicatives and it just makes it easier to see what is going on. So, I do not think I would ever want to write <*> operator that works over any "applicative" in practice in F#.

That said, the issue with your code is that the <*> operator uses the same ^A type parameter for both arguments and the result (while they are different types in the call) - if you use three separate type parameters it works fine:

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


来源:https://stackoverflow.com/questions/37949413/how-to-do-a-applicative-in-f

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!