Search code examples
haskellghci

Haskell regex context ambiguous type despite explicit Bool type annotation, succeeds in ghci


This works in an interpreter session

λ> import Text.Regex.Base
λ> import Text.Regex.Posix
λ> import Data.List (sort)
λ> import System.Directory

λ> ls <- getDirectoryContents "."
λ> let csvs = sort $ filter (\x -> x =~ "csv$" :: Bool) ls
λ> recent = last csvs

This is great and gives me exactly what I need.

However, the same code fails to compile in a script:

t10.hs:40:35-45: error: …
    • Ambiguous type variable ‘source0’ arising from a use of ‘=~’
      prevents the constraint ‘(RegexMaker
                                  Regex CompOption ExecOption source0)’ from being solved.
      Probable fix: use a type annotation to specify what ‘source0’ should be.
      These potential instances exist:
        instance RegexMaker Regex CompOption ExecOption C.ByteString
          -- Defined in ‘Text.Regex.Posix.ByteString’
        instance RegexMaker Regex CompOption ExecOption LB.ByteString
          -- Defined in ‘Text.Regex.Posix.ByteString.Lazy’
    • In the expression: x =~ "csv$" :: Bool
      In the first argument of ‘filter’, namely
        ‘(\ x -> x =~ "csv$" :: Bool)’
      In the second argument of ‘($)’, namely
        ‘filter (\ x -> x =~ "csv$" :: Bool) ls’
t10.hs:40:40-45: error: …
    • Ambiguous type variable ‘source0’ arising from the literal ‘"csv$"’
      prevents the constraint ‘(Data.String.IsString
                                  source0)’ from being solved.
      Probable fix: use a type annotation to specify what ‘source0’ should be.

I have an explicit :: Bool context at the end to provide exactly this information. Why would this be succeeding in ghci but failing to catch this same instruction when compiling, and how can I fix it?


Solution

  • The ambiguity is not about what the type of x =~ "csv$" is - that is already determined from your use of filter. The problem is the "csv$" literal itself. Based on the error message, you have the OverloadedStrings language extension enabled. The ambiguity here is figuring out which type of string "csv$" needs to be.

    Your solution is to either

    • turn off OverloadedStrings (if you don't need it for this module), or
    • add a type annotation to "csv$", so you have \x -> x =~ ("csv$" :: String) instead of \x -> x =~ "csv$" :: Bool

    If this is a problem that is cropping up a lot, you may want to play with the ExtendedDefaultRules and have a default declaration in your file.

    The reason this succeeds in GHCi is probably because because you didn't have OverloadedStrings enabled there (or possibly due to GHCi's different defaulting rules).