Re: Using implicit parameter constraints in data decl
On Sunday 07 November 2004 20:09, Simon Peyton-Jones wrote: | Definitely a bug. Could you pls make a small module that elicits the | bug, and send it to me? Here it is:
module Test where
data Test = (?val::Bool) => Test { name :: String }
instance Show Test where show p = name p
franksen@linux: .../src/testbug > ghc -fimplicit-params TestBug.hs ghc-6.2.2: panic! (the `impossible' happened, GHC version 6.2.2): simplCore/Simplify.lhs:1473: Non-exhaustive patterns in function cat_evals BTW, I see now that the data declaration is syntactically wrong. Anyway, the (syntactically) correct version data (?val::Bool) => Test = Test { name :: String } is rejected by the compiler: TestBug.hs:3: Illegal constraint ?val :: Bool In the context: (?val :: Bool) While checking the context of the data type declaration for `Test' In the data type declaration for `Test' which is unfortunate since it means that you cannot put a function that depends on an implicit parameter into a data structure. There are probably technical reasons for this restriction, but it means that such functions are no longer first class objects. Cheers, Ben
Benjamin Franksen wrote:
data (?val::Bool) => Test = Test { name :: String }
is rejected by the compiler:
TestBug.hs:3: Illegal constraint ?val :: Bool In the context: (?val :: Bool) While checking the context of the data type declaration for `Test' In the data type declaration for `Test'
which is unfortunate since it means that you cannot put a function that depends on an implicit parameter into a data structure.
Does this do what you want?: data Test = Test { name :: (?val::Bool) => String } -- Ben
On Sunday 07 November 2004 23:19, Ben Rudiak-Gould wrote:
Benjamin Franksen wrote:
data (?val::Bool) => Test = Test { name :: String }
is rejected by the compiler:
TestBug.hs:3: Illegal constraint ?val :: Bool In the context: (?val :: Bool) While checking the context of the data type declaration for `Test' In the data type declaration for `Test'
which is unfortunate since it means that you cannot put a function that depends on an implicit parameter into a data structure.
Does this do what you want?:
data Test = Test { name :: (?val::Bool) => String }
Thanks for the hint, but no: TestBug.hs:4: Illegal constraint ?val :: Bool In the type: ({?val :: Bool} => String) -> Test While checking the type of constructor `Test' In the data type declaration for `Test' Ben
Benjamin Franksen wrote:
On Sunday 07 November 2004 23:19, Ben Rudiak-Gould wrote:
Does this do what you want?:
data Test = Test { name :: (?val::Bool) => String }
Thanks for the hint, but no:
TestBug.hs:4: Illegal constraint ?val :: Bool In the type: ({?val :: Bool} => String) -> Test While checking the type of constructor `Test' In the data type declaration for `Test'
Try using -fglasgow-exts instead of -fimplicit-params. Without glasgow-exts you can't use nested contexts in any circumstances; e.g. you can't write test :: ((?val::Bool) => String) -> () which is (similar to) the type that the data constructor Test needs to have. -- Ben
On Sunday 07 November 2004 19:36, Benjamin Franksen wrote:
data (?val::Bool) => Test = Test { name :: String }
is rejected by the compiler [...] which is unfortunate since it means that you cannot put a function that depends on an implicit parameter into a data structure. There are probably technical reasons for this restriction, but it means that such functions are no longer first class objects.
Here is an executive summary lest anyone gets false ideas: Functions with implicit parameters *are* first class values but only if you use -fglasgow-exts and not only -fimplicit-params. The version above is rejected nonetheless (for whatever reason I can't figure out at the moment) but data Test = Test { name :: (?val::Bool) => String } works. The compiler flag is needed because in Haskel98 contexts may not appear after the 'data' (i.e. the way I tried it at first) and -fglasgow-exts lifts this restriction. I haven't found this explicitly mentioned in the ghc docs, but that doesn't mean it's not there somewhere. References: http://www.haskell.org/onlinelibrary/decls.html Thanks to Ben Rudiak-Gould who helped me to resolve this. Cheers, Ben -- Top level things with identity are evil. -- Lennart Augustsson
Benjamin Franksen wrote:
Functions with implicit parameters *are* first class values but only if you use -fglasgow-exts and not only -fimplicit-params.
Careful, they're still not entirely first class. For example, you can't pass types with implicit parameters as arguments to type constructors, so "IO ((?val::Bool) => String)" will still be rejected, even with -fglasgow-exts. (While experimenting with this, I discovered to my surprise that GHCi accepts the type "IO ((Num a) => a)", and describes it as "forall a. IO ({Num a} => a)". However it rejects "return 12 :: IO ((Num a) => a)", saying that it can't deduce (Num ({Num a} => a)). Is this a bug?)
The version above is rejected nonetheless (for whatever reason I can't figure out at the moment)
There's actually a good reason for this. The three declarations data (?val::Bool) => Test = Test { name :: String } data Test = (?val::Bool) => Test { name :: String } data Test = Test { name :: (?val::Bool) => String } all mean different things. The first one makes (?val::Bool) a constraint on the type constructor Test, meaning that any type that mentions Test will be required to have a (?val::Bool) context also. This is basically useless in practice, since it just adds a dummy function parameter which is (in general) never actually used. Type-class constraints in this position are deprecated, and I guess implicit-parameter constraints were never allowed in the first place. The second declaration makes (?val::Bool) a constraint on the *data* constructor Test, so the data constructor gets the type (?val::Bool) => String -> Test. The constructor stores the value of ?val in a second quasi-hidden field in the constructed value. When it's later deconstructed by pattern matching, the value becomes "available" again, even though it doesn't appear explicitly in the pattern. This has a clear semantics for type-class constraints because they are always attached to particular explicit values, but I don't know how much sense it makes for implicit parameters. The third declaration makes (?val::Bool) a constraint on a particular *field* of the data constructor, so Test has the type ((?val::Bool) => String) -> Test. This simply constrains the type of that field. There are no extra hidden fields. -- Ben
participants (2)
-
Ben Rudiak-Gould -
Benjamin Franksen