Why does this function that uses a scoped type variable in a where clause not typecheck?

前端 未结 1 1158
天命终不由人
天命终不由人 2020-12-06 19:04

I have a function that has a value defined in a where clause, and I want to give it an explicit type annotation. The annotation needs to use a type variable fro

相关标签:
1条回答
  • 2020-12-06 19:22

    You need an explicit forall:

    {-# LANGUAGE ScopedTypeVariables #-}
    
    import Control.Monad.Trans.Except
    import Data.Functor.Identity
    
    f :: forall a. ExceptT String Identity a -> Maybe a
    f m = Nothing
      where x :: Identity (Either String a)
            x = runExceptT m
    

    but why

    That is a great question. This appears to be a rule of ScopedTypeVariables. We know in GHC Haskell that all top-level variables are implicitly forall'd, as documented here. One would suspect that the GHC devs added this behavior for backwards compatibility: without this rule, a file without the extension turned on could stop type-checking once the extension was turned on. We can easily imagine a scenario where helper functions declared in the where block to inadvertently reuse the common type variable names a, b, c, t, so on. It would be great if someone could find the exact spot in the GHC source code where this distinction between explicit and implicit forall'd variables arose.

    update

    Here we go (although this is all guesswork from the comments and grepping):

    • While type-checking user signatures, the function tcUserTypeSig invokes findScopedTyVars. TcBinds.hs:ef44606:L1786

    • findScopedTyVars in TcRnTypes filters for foralls by calling tcSplitForAllTys. TcRnTypes.hs:ef44606:L1221

    • Which is a wrapper around splitForAllTys, which folds over a type's subtypes to build up a list of type variables introduced by foralls. Types/Type.hs:ef44606:L1361

    0 讨论(0)
提交回复
热议问题