Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to do a Applicative in F#?

Tags:

generics

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(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?

like image 804
robkuz Avatar asked Jun 21 '16 16:06

robkuz


People also ask

What is applicative in functional programming?

In functional programming, an applicative functor, or an applicative for short, is an intermediate structure between functors and monads.

Is functor a Typeclass?

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.

Is Fmap a functor?

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.

Is every applicative a Monad?

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.


1 Answers

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'
like image 165
Tomas Petricek Avatar answered Oct 04 '22 11:10

Tomas Petricek