haskelltypeclasstrifecta

Ambiguous type variable when updating two record fields at a time (but not when updating one!)


The following code fails with an "ambiguous type variable" error (bottom). However, an alternate definition which updates the record twice works just fine: why is this? Further, the "broken" definition below is very similar to the one in the Trifecta source. I'm compiling with GHC 7.10.3 against trifecta 1.5.2 and parsers 0.12.3.

module Main where

import Text.Trifecta
import Text.Parser.Token.Style as T

-- This definition causes a type error
identStyle :: TokenParsing m => IdentifierStyle m
identStyle =
  T.emptyIdents
    { _styleStart    = letter
    , _styleLetter   = letter
    }

Here is the working (alternative) definition

identStyle :: TokenParsing m => IdentifierStyle m
identStyle = T.emptyIdents { _styleStart = letter } { _styleLetter = letter }

The error generated by the first definition is:

Main.hs:10:3:
    Could not deduce (TokenParsing t0)
      arising from a use of ‘emptyIdents’
    from the context (TokenParsing m)
      bound by the type signature for
                 identStyle :: TokenParsing m => IdentifierStyle m
      at Main.hs:8:15-49
    The type variable ‘t0’ is ambiguous
    Note: there are several potential instances:
      instance attoparsec-0.13.0.1:Data.Attoparsec.Internal.Types.Chunk
                 t =>
               TokenParsing
                 (attoparsec-0.13.0.1:Data.Attoparsec.Internal.Types.Parser t)
        -- Defined in ‘Text.Parser.Token’
      instance TokenParsing Text.ParserCombinators.ReadP.ReadP
        -- Defined in ‘Text.Parser.Token’
      instance TokenParsing m => TokenParsing (Unhighlighted m)
        -- Defined in ‘Text.Parser.Token’
      ...plus 11 others
    In the expression: emptyIdents
    In the expression:
      emptyIdents {_styleStart = letter, _styleLetter = letter}
    In an equation for ‘identStyle’:
        identStyle
          = emptyIdents {_styleStart = letter, _styleLetter = letter}
Failed, modules loaded: none.

Solution

  • Hah, this is kind of a funny problem.

    The issue here is that emptyIdents is class-polymorphic. So when you use it, some part of the type inference algorithm has to define which instance to use.

    When you modify only one field at a time, the type of the record isn't permitted to change; that is, the type of \record -> record { _styleStart = undefined } is IdentifierStyle m -> IdentifierStyle m. So by demanding that the final type of

    emptyIdents { _styleStart = letter } { _styleLetter = letter }
    

    is IdentifierStyle m, we can infer that the first emptyIdents is also IdentifierStyle m with the same type m as argument.

    On the other hand, thanks to how record update works in Haskell, when you update both fields at once (which happens to be all the fields whose types mention the type argument m), the update becomes polymorphic. That is, the type of \record -> record { _styleStart = undefined, _styleLetter = undefined } is IdentifierStyle m' -> IdentifierStyle m -- note the prime!

    So in the case where you do both updates at once like

    emptyIdents { _styleStart = letter, _styleLetter = letter }
    

    then fixing the final type of this update at IdentifierStyle m does not determine the type of emptyIdents.

    There's half a dozen ways to fix this, but the basic idea is that you should fix an instance to use while building emptyIdents.