[GHC] #12882: Unexpected constraint when using ExistentialQuantification

#12882: Unexpected constraint when using ExistentialQuantification -------------------------------------+------------------------------------- Reporter: danilo2 | Owner: Type: bug | Status: new Priority: high | Milestone: Component: Compiler | Version: 8.0.1 (Type checker) | Keywords: | Operating System: Unknown/Multiple Architecture: | Type of failure: None/Unknown Unknown/Multiple | Test Case: | Blocked By: Blocking: | Related Tickets: Differential Rev(s): | Wiki Page: -------------------------------------+------------------------------------- Hello! Consider this simple code: {{{ data Elem t = Typeable t => Elem Int tst1 :: forall a. Elem a -> TypeRep tst1 (Elem _) = typeRep (Proxy :: Proxy a) }}} It works and it should work. `Elem` is created only to be sure that if we've got a value of type `Elem t` we don't have to check that `t` is `Typeable`. <offtopic> By the way, exystential newtypes would be so awesome in GHC! </offtopic> And now a strange thing. If we create another function: {{{ tst2 :: forall a. Elem a -> TypeRep tst2 _ = typeRep (Proxy :: Proxy a) }}} GHC throws error that there is no `Typeable a` constraint. The only difference between `tst1` and `tst2` is different pattern binding. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/12882 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#12882: Unexpected constraint when using ExistentialQuantification -------------------------------------+------------------------------------- Reporter: danilo2 | Owner: Type: bug | Status: new Priority: high | Milestone: Component: Compiler (Type | Version: 8.0.1 checker) | Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by mpickering): Can you paste your whole file please? It isn't clear which extensions you have turned on to get the first example to compile. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/12882#comment:1 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#12882: Unexpected constraint when using ExistentialQuantification -------------------------------------+------------------------------------- Reporter: danilo2 | Owner: Type: bug | Status: closed Priority: normal | Milestone: Component: Compiler (Type | Version: 8.0.1 checker) | Resolution: invalid | Keywords: Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Changes (by rwbarton): * priority: high => normal * status: new => closed * resolution: => invalid Comment:
The only difference between `tst1` and `tst2` is different pattern binding.
Different forms of pattern binding have different semantics. Here the pattern match is required to ensure that the argument was actually built with the `Elem` constructor, so that it contains a `Typeable a` dictionary. Since `tst2` ignores its argument, it should be fine to write `tst2 undefined`, but then where does the `Typeable` instance come from? In contrast, `tst1 undefined` clearly diverges. For the same reason, it doesn't make sense here to make `data Elem t = Typeable t => Elem Int` into a newtype, since it holds two pieces of data: a `Typeable t` dictionary and an `Int`. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/12882#comment:2 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#12882: Unexpected constraint when using ExistentialQuantification -------------------------------------+------------------------------------- Reporter: danilo2 | Owner: Type: bug | Status: closed Priority: normal | Milestone: Component: Compiler (Type | Version: 8.0.1 checker) | Resolution: invalid | Keywords: Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by mpickering): OK - I got it to compile now, I was missing scoped type variables. Here is the more usual way to write your data type. {{{ {-# LANGUAGE ExistentialQuantification #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE GADTs #-} import Data.Typeable data Elem t where Elem :: Typeable t => Int -> Elem t tst1 :: forall a. Elem a -> TypeRep tst1 (Elem _) = typeRep (Proxy :: Proxy a) }}} Then it is clear why you must pattern match on `Elem` in order to discover that you have the `Typeable` constraint. You could have another constructor which doesn't bind it. For example, {{{ data Elem t where Elem :: Typeable t => Int -> Elem t Elem2 :: t -> Elem t }}} -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/12882#comment:3 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#12882: Unexpected constraint when using ExistentialQuantification -------------------------------------+------------------------------------- Reporter: danilo2 | Owner: Type: bug | Status: closed Priority: normal | Milestone: Component: Compiler (Type | Version: 8.0.1 checker) | Resolution: invalid | Keywords: Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by danilo2): rwbarton, mpickering: very interesting, thanks for clarification! By the way, is there any other way to create `Elem`-like newtype, which will just ensure GHC that this constraint would be meet? I dont want to pass the dictionary in runtime. I just want to tell the type system that if I ever created `Elem t`, `t` is Typeable. The reason behind it is that I dont want constraint on `t` to appear on functions processing `Elem t`. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/12882#comment:4 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#12882: Unexpected constraint when using ExistentialQuantification -------------------------------------+------------------------------------- Reporter: danilo2 | Owner: Type: bug | Status: closed Priority: normal | Milestone: Component: Compiler (Type | Version: 8.0.1 checker) | Resolution: invalid | Keywords: Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by rwbarton): But presumably the reason you want the type checker to know `t` is an instance of `Typeable` is in order to use functions which use the constraint, like `typeRep`. And the `Typeable t` dictionary is exactly what will be used at runtime to implement that function. So, there is no getting around the need for the dictionary, either passed into your function as a constraint `Typeable t =>` or unpacked from the data as in `tst1`. (I'm a bit confused how you think this could work at runtime. Maybe you are imagining that a function receives information about its type parameters at runtime and could use that data to look up the needed `Typeable` instance in some global table? Actually, there is no type data at runtime aside from what you explicitly introduce in the form of `Typeable` contexts nor any table of instances. And even `Typeable` is not that special, and could be reimplemented to some extent by a used-defined class.) -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/12882#comment:5 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#12882: Unexpected constraint when using ExistentialQuantification -------------------------------------+------------------------------------- Reporter: danilo2 | Owner: Type: bug | Status: closed Priority: normal | Milestone: Component: Compiler (Type | Version: 8.0.1 checker) | Resolution: invalid | Keywords: Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by danilo2): rwbarton: hmm, I dont know so deeply how GHC solves the things under the hood, but I imagine GHC could easily allow such code: {{{ class Foo a where foo :: a -> Int newtype ImplicitFoo a = Foo a => ImplicitFoo a getFoo :: ImplicitFoo a -> Int getFoo (ImplicitFoo a) = foo a }}} The constraint in the newtype just tells that if `ImplicitFoo` was ever constructed by somebody, the constraint was already met, so there is no need to check it again and pass along functions. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/12882#comment:6 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#12882: Unexpected constraint when using ExistentialQuantification -------------------------------------+------------------------------------- Reporter: danilo2 | Owner: Type: bug | Status: closed Priority: normal | Milestone: Component: Compiler (Type | Version: 8.0.1 checker) | Resolution: invalid | Keywords: Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by rwbarton): Well there is no problem if you write `data` instead of `newtype`, above. But of course the `Foo a` dictionary must be stored within an `ImplicitFoo a`, so that it can provide the implementation of `foo` at runtime. You cannot think of the constraint `Foo a` as a box to be checked off to satisfy some bureaucratic type checker. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/12882#comment:7 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler
participants (1)
-
GHC