Opened 3 years ago

Closed 6 months ago

Last modified 6 months ago

#6022 closed bug (duplicate)

GHC infers over-general types

Reported by: simonpj Owned by: simonpj
Priority: normal Milestone: 7.10.1
Component: Compiler Version: 7.4.1
Keywords: Cc: hackage.haskell.org@…
Operating System: Unknown/Multiple Architecture: Unknown/Multiple
Type of failure: None/Unknown Test Case: typecheck/should_fail/T6022
Blocked By: Blocking:
Related Tickets: #8883 Differential Revisions:

Description

Consider

f x = x + head

GHC will (with no flags) will compile this almost-certainly-wrong program, giving f the type

    f :: forall a. Num ([a] -> a) => ([a] -> a) -> [a] -> a

There's nothing wrong with that type, and in principle someone might later define a suitable instance of Num, but (a) it's not Haskell 98, and (b) it's unlikely to be right, so we've deferred a type error from the definition site of f to the (perhaps much later) call site.

I think GHC should complain, and require a type signature if that's what you really want. This came up on Stackoverflow

Change History (12)

comment:1 Changed 3 years ago by igloo

  • Milestone changed from 7.6.1 to 7.6.2

comment:2 follow-up: Changed 3 years ago by carter

While this is likely wrong code, it is perfectly reasonable to have vector function num instances! (its not overly general, its just not pedagogically helpful for new people starting in haskell)

eg given Num a , the instance Num (Vector a -> a), has a perfectly natural (and useful) definition. and thus a Num instance for [a]-> a is reasonable too!

however, maybe an alternative approach would be add a suppressable warning for when a type class constraint is used which has no known instances?

here are example "similar ways" to write the same function, and their respective types, in ghci 7.6.1

Prelude> let g x = (+) x $ head
Prelude> :t g
g :: Num ([a] -> a) => ([a] -> a) -> [a] -> a

Prelude> let h x y = x + head y
Prelude> :t h
h :: Num a => a -> [a] -> a

Prelude> let q x = (x +) . head
Prelude> :t q
q :: Num c => c -> [c] -> c

so it seems that the core of the issue in the case of the bad example in this ticket is a syntactical one of making the intended composition. Likewise, I think this isn't a bug, the type checker is giving a type that the user can look at and see is "wrong" for their code!

i think rejecting code with that Num instance constraint would be bad.
Unless someone has a counter point, I think this issue should be closed.

comment:3 in reply to: ↑ 2 Changed 3 years ago by carter

fixed the formatting

Prelude> let g x = (+) x $ head
Prelude> :t g

g
Num ([a] -> a) => ([a] -> a) -> [a] -> a

Prelude> let h x y = x + head y

Prelude> :t h

h : Num a => a -> [a] -> a

Prelude> let q x = (x +) . head

Prelude> :t q

q : Num c => c -> [c] -> c

comment:4 Changed 3 years ago by maeder

Why is this not Haskell 98? Well, hugs rejects this:

- Cannot infer instance
*** Instance   : Num ([a] -> a)
*** Expression : f

But I don't know why, it works with "hugs -98". I cannot make ghc reject it, so ghc does not support Haskell 98!

In any case, I agree with "carter" that it should not be rejected (by default). If you ignore
warnings like "no type signature" it is your own fault!

comment:5 Changed 3 years ago by igloo

  • Milestone changed from 7.6.2 to 7.8.1
  • Owner set to simonpj

comment:6 Changed 2 years ago by liyang

  • Cc hackage.haskell.org@… added

comment:7 Changed 13 months ago by thoughtpolice

  • Milestone changed from 7.8.3 to 7.10.1

Bumping priority down (these tickets haven't been closely followed or fixed in 7.4), and moving out to 7.10 and out of 7.8.3.

comment:8 Changed 13 months ago by thoughtpolice

  • Priority changed from high to normal

Actually dropping priority. :)

comment:9 Changed 6 months ago by thomie

GHC should reject f without type signature, because it also rejects f with type signature, unless FlexibleContexts is enabled.

Prelude> let f x = x + head  -- GHC should complain here

Prelude> :t f
f :: Num ([a] -> a) => ([a] -> a) -> [a] -> a

Prelude> let f :: Num ([a] -> a) => ([a] -> a) -> [a] -> a; f x = x + head

<interactive>:4:10:
    Non type-variable argument in the constraint: Num ([a] -> a)
    (Use FlexibleContexts to permit this)
    In the type signature for ‘f’:
      f :: Num ([a] -> a) => ([a] -> a) -> [a] -> a

Prelude> :set -XFlexibleContexts

Prelude> let f :: Num ([a] -> a) => ([a] -> a) -> [a] -> a; f x = x + head

Prelude> 

comment:10 Changed 6 months ago by thomie

  • Resolution set to duplicate
  • Status changed from new to closed

I now realize HEAD does exactly that, see #8883. I'm not sure if an extra regression test is needed, but here's what it would look like:

$ cat T6022.hs 
module T6022 where
f x = x + head

$ ghc-7.9.20141125 T6022.hs 
[1 of 1] Compiling T6022            ( T6022.hs, T6022.o )

T6022.hs:2:1:
    Non type-variable argument in the constraint: Num ([a] -> a)
    (Use FlexibleContexts to permit this)
    When checking that ‘f’ has the inferred type
      f :: forall a. Num ([a] -> a) => ([a] -> a) -> [a] -> a
Last edited 6 months ago by thomie (previous) (diff)

comment:11 Changed 6 months ago by Simon Peyton Jones <simonpj@…>

In 4721167a0118e4c8bc6c8266c3357a8a2ac4f4e2/ghc:

Trac #6022 is actually fine now

comment:12 Changed 6 months ago by simonpj

  • Test Case set to typecheck/should_fail/T6022

And the test was actually there, just marked as broken!

Note: See TracTickets for help on using tickets.