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?
In functional programming, an applicative functor, or an applicative for short, is an intermediate structure between functors and monads.
Functor in Haskell is a typeclass that provides two methods – fmap and (<$) – for structure-preserving transformations. To implement a Functor instance for a data type, you need to provide a type-specific implementation of fmap – the function we already covered.
The expression fmap (*2) is a function that takes a functor f over numbers and returns a functor over numbers. That functor can be a list, a Maybe , an Either String, whatever. The expression fmap (replicate 3) will take a functor over any type and return a functor over a list of elements of that type.
All monads are applicative functors, but not all applicative functors are monads. As the set diagram reiterates, applicative functors are functors, but again: not necessarily the other way around.
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'
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With