How to make applicative in F #?

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(fx) | Error(e), Success(_) -> Error(e) | Success(_), Error(e) -> Error(e) | Error(e1), Error(e2) -> Error(List.concat [e1;e2]) 

and the following built-in 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' 

All this is an attempt to imitate the Haskells Applicative, and the signature should be

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

But I do not know that there is no way to express this in F #

Any ideas on how to do this?

+5
source share
1 answer

In general, I think that it is not recommended to try to emulate Haskell templates in F #. In Haskell, a lot of code is written as very general, because monads and applicators are used more often.

In F #, I prefer to write more specialized code because you don’t need to write polymorphic code over monads or applications, and it just makes it easier to see what happens. Thus, I don’t think that I will ever want to write a <*> operator that works on any “applicative” practice in F #.

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

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

All Articles