question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Slow compiler performance in Monad Transformers sample with Visual Studio, and can't give hints.

See original GitHub issue

When I try Monad Tranformers sample with Visual Studio 2015 along with F# PowerTools, I noticed that the CPU peaks when IDE sits idle, probably due to type inference engine and syntax colorization is delayed for few seconds.

I am not sure if this issue is related to F# compiler , VisualFSharp or FSharpPlus. Can you suggest me any workarounds like putting a hint to make IDE happy for better performance ? Also when I explicitly give type like below:

let getValidPassword : ErrorT<Async<_>> =
monad {
    let! s = liftAsync getLine
    if isValid s then return s
    else return! throw -1
}
</ catch /> (fun s -> throw ("The error was: " + decodeError s))

Notice Error<Async<_>>

`I get errors like below :

  • Could not resolve the ambiguity inherent in the use of the operator ‘Bind’ at or near this program point. Consider using type annotations to resolve the ambiguity.
  • Could not resolve the ambiguity inherent in the use of the operator ‘LiftAsync’ at or near this program point. Consider using type annotations to resolve the ambiguity.
  • Type constraint mismatch when applying the default type ‘obj’ for a type inference variable. No overloads match for method ‘LiftAsync’. The available overloads are shown below (or in the Error List window). Consider adding further type constraints

Why is that so ?

Issue Analytics

  • State:open
  • Created 7 years ago
  • Comments:16 (9 by maintainers)

github_iconTop GitHub Comments

2reactions
gustycommented, Dec 14, 2016

There is a known issue in the F# compiler which makes overload resolution very slow in cases like this.

Fortunately this was solved in F# 4.1 so if you want to play with this at a decent compiler speed will need to wait for Visual Studio RC2 or download the compiler from github.

Regarding the type annotation yes, they are tricky. That’s most likely something that can be improved in the F# compiler as well but the current status is that the less you tell the smarter they are, otherwise you have to go to full type annotations:

let getValidPassword : ErrorT<Async<Choice<string,string>>> =
    monad {
        let! s = lift getLine : ErrorT<Async<Choice<string,int>>>
        if isValid s then return s
        else return! (throw -1 : ErrorT<Async<Choice<string,int>>>) }
    </catch/>
        (fun s -> throw ("The error was: " + decodeError s))

let askPassword : ErrorT<Async<Choice<string,string>>> = monad {
    do! ( (lift <| putStrLn "Insert your new password:") : ErrorT<Async<Choice<unit,string>>>)
    let! value = getValidPassword : ErrorT<Async<Choice<string,string>>>
    do! lift <| putStrLn "Storing in database..." : ErrorT<Async<Choice<unit,string>>>
    return value}

But that’s not a good workaround and it doesn’t speed up a lot. The problem is the use of the generic code, in this sample the code is extremely generic, even more generic that the Haskell version since catch changes the type of the error.

A good workaround for this is not to use generic code, however in Monad Transformers it’s difficult not to use generic code at all because you will need concrete functions for each combinations of monads.

Still it would be possible to create less generic code in idiomatic F# style. Something like ErrorT.catch instead of just catch indeed there are already many functions like ErrorT.map and so on but we need to add more.

When I got time I will add more less generic functions.

Finally note that Monad Transformers are really experimental though I started a project that makes heavy use of them and the compile time is not an issue when using F# 4.1.

Thanks for the report.

1reaction
gustycommented, Oct 27, 2021

Looks like the F# compiler didn’t improve that much in this time. Anyway, I was experimenting with a technique called type defunctionalization and managed to improve type inference in monad transformers, but it requires a substantial change in the library. I’m keeping it for v2. Then in the compiler side of things there is a longstanding PR to take extensions methods into account for overload resolution which I think will reduce the level of hacking currently required to plumb everything together.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Expected performance drop while using monad ...
Classic Writer tends to be extremely slow. Maybe the exact use case here differs from that in ways that make it not so...
Read more >
Odd results from monad transformer benchmark. A bug?
The benchmark tells me that running WriterT String IO is 20 times(!) slower than running plain IO , even when not using tell...
Read more >
Tips to improve performance - Visual Studio (Windows)
Learn how to optimize certain Visual Studio features that you might not be using to help improve performance.
Read more >
What is your least favorite thing about Haskell in 2018?
Laziness, compiling speed. Slow compilation speed, slow binary startup cost, slow interpreter. Honestly considering learning OCaml to use as ...
Read more >
Learning Haskell is no harder than learning any other ...
The biggest lie about Haskell is that it's easy to learn. No it's not, and I do use it at work. Sure, it's...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Hashnode Post

No results found