Two functions compile with type annotations. Delete one annotation - does not compile. Remove the two compilations again. What for?

Check out this Reflex program:

{-# LANGUAGE ScopedTypeVariables, RecursiveDo #-} import Control.Applicative import Control.Monad import Control.Monad.IO.Class import Prelude hiding (div) import Reflex.Dom import qualified Data.Map as M clickMe :: MonadWidget tm => m (Event t ()) clickMe = do rec (e,_) <- elAttr' "button" M.empty (display c) c :: Dynamic t Int <- count (domEvent Click e) return $ domEvent Click e div :: forall tma . MonadWidget tm => ma -> ma div = elAttr "div" ("style" =: "border : 1px solid black") app :: forall tm . MonadWidget tm => m () app = div $ do aClicks <- clickMe bClicks <- clickMe a <- count aClicks b <- count bClicks l <- combineDyn (\ab -> replicate (ab) ()) ab simpleList l (const clickMe) return () main = mainWidget app 

If you remove the type annotation from a div or app , the program will not compile with a huge, scary type error. If you delete both, it will be compiled again. From a programmer’s point of view, this gives a terrible user experience when someone tries to annotate a non-automated program in stages. It makes no sense that adding the correct type annotation to an unannotated term causes a compiler error, and this makes the programmer think that he has incorrectly assigned the type.

This is the error you get by removing the div annotation.

These are inferred types.

Why is this happening?

+7
types type-systems haskell
source share
2 answers

This is due to the restriction of monomorphism. When the compiler checks the top-level binding without annotating the type, it will not assign a polymorphic type if that type has a constraint and the function does not have a syntactic argument, which is the case for both of your functions.

However, if you do not include the type signature, it still does not compile. In your case, you provided him with additional information (part of foo = [app, _] ) and for some reason decided to choose a monomorphic type - I do not know what has changed in your environment, but this is not standard behavior.

Here is a simple file that redirects the problem you are having:

 {-# LANGUAGE RankNTypes, KindSignatures, MultiParamTypeClasses, FunctionalDependencies #-} module Test where import Prelude hiding (div) class MonadWidget t (m :: * -> *) | m -> t div :: forall tma . MonadWidget tm => ma -> ma div = (undefined :: forall tma . MonadWidget tm => ma -> ma) app :: forall tm . MonadWidget tm => m () app = (div (undefined :: forall tm . MonadWidget tm => m ()) :: forall tm . MonadWidget tm => m () ) 

If you comment out either a type signature, or both, you will encounter an error. However, comment out any signature of the top-level type, but run it with ghc -XNoMonomorphismRestriction Test.hs and it will be successfully compiled in each configuration. Here are a few tests ,

+4
source share

As Raid Barton noted in the comments, this is due to the limited restriction of monomorphism .

Here is a simplified example:

 foo :: Monad m => ma -> ma foo = (>>= return) bar :: Monad m => m () bar = foo (return ()) 

When monomorphism restriction and foo type signature are enabled:

  • GHC tries to assign the monomorphic type foo and fails because there is no default Monad instance:

There is no instance for (Monad m0) associated with using 'β†’ =
A variable of type m0 is ambiguous

  • using foo at bar leads to another error that I cannot explain

Failed to match type 'm0 with' m
because a variable of type m disappears from scope

Adding {-# LANGUAGE NoMonomorphismRestriction #-} pragma fixes this and allows you to add type signatures gradually.

+1
source share

All Articles