Opened 7 years ago

Closed 7 years ago

Last modified 6 years ago

#981 closed bug (fixed)

implicit parameters, type synonyms, and $

Reported by: jefb@… Owned by:
Priority: normal Milestone:
Component: Compiler Version: 6.6
Keywords: Cc:
Operating System: MacOS X Architecture: Unknown/Multiple
Type of failure: Difficulty: Unknown
Test Case: tc222 Blocked By:
Blocking: Related Tickets:

Description

This is related to ticket #821 (which is indeed fixed in 6.6).

We make extensive use of an (undocumented?) feature of GHC: type synonyms can include implicit parameter constraints such that when the type is used, the constraint 'floats to the top'. This appears to be broken in some cases in 6.6.

Here's an example module:

{-# OPTIONS -fglasgow-exts -fimplicit-params #-}
module TestIP where

type PPDoc = (?env :: Int) => Char

f :: Char -> PPDoc
f c = g $ c

g :: PPDoc -> PPDoc
g d = d

when loaded in ghci 6.6, this yields:

/Users/jefb/Test.hs:7:10:
    Couldn't match expected type `PPDoc' against inferred type `Char'
    Probable cause: `c' is applied to too many arguments
    In the second argument of `($)', namely `c'
    In the expression: g $ c

If g $ c is changed to g c the module compiles.

The example compiles in 6.4.1 (I don't have handy access to other versions right now).

Thanks!
Jef

Change History (4)

comment:1 Changed 7 years ago by dons

I've seen exactly this in lambdabot too: the issue with $. It emerged
sometime just after the impredicativty changes.

I took it as a sign from above (or from Cambridge) to remove implicit parameters from the bot.

comment:2 Changed 7 years ago by benl

I don't think the type synonyms are the problem here.

For the following code,

f c = g $ c

g :: ((?env :: Int) => Char) -> ((?env :: Int) => Char)
g d = d

6.4.1 infers

f :: (?env::Int) => Char -> Char

but 6.7 infers

f :: (?env::Int) => ((?env::Int) => Char) -> Char

If you add either sig to 6.4.1 then it's happy, but 6.7 chokes on both with

    Couldn't match expected type `(?env::Int) => Char'
           against inferred type `Char'
    In the second argument of `($)', namely `c'
    In the expression: g $ c
    In the definition of `f': f c = g $ c

I'll need to think some more about whether it's a good idea to make these two equivalent ... but notice that if you change the type Char to (Char -> Char):

f :: ((?env :: Int) => (Char -> Char)) -> ((?env :: Int) => (Char -> Char))
f c = g $ c

g :: ((?env :: Int) => (Char -> Char)) -> ((?env :: Int) => (Char -> Char))
g d = d

then 6.4.1 is still happy, but 6.7 gives

    Couldn't match expected type `?env::Int'
           against inferred type `Char'
    Probable cause: `c' is applied to too many arguments
    In the second argument of `($)', namely `c'
    In the expression: g $ c

Now it's comparing the constraint for the implicit parameter with the type Char. Bad news methinks.

comment:3 Changed 7 years ago by simonpj

  • Resolution set to fixed
  • Status changed from new to closed
  • Test Case set to tc222

Well this one was harder than it looks. The culprit, again, was an impredicative use of ($), in the definition of f. However, this was confused and concealed by a bug that meant that some parts of the type checker weren't recognising (?x::Int => stuff) as a polytype, because it doesn't have any leading foralls.

It's a bit unclear to me why 6.4.2 accepts this program; indeed it might even be classed as a bug. I won't investigate that further.

Anyway, since the combination of higher-rank functions and ($) keeps coming up, I have bitten the bullet, and arranged that all uses of ($) and similar functions should now work, but allowing information flow left-to-right among arguments. So in the call (runST $ foo), we first figure out how to instantiate ($)'s arguments based on the first arg (runST), and then use that to typecheck the second arg. A version of ($) with argument order reversed would not work.

Let's see if that helps.

Meanwhile, this program works fine.

Simon

comment:4 Changed 6 years ago by simonmar

  • Architecture changed from Unknown to Unknown/Multiple
Note: See TracTickets for help on using tickets.