RE: Primitive types and Prelude shenanigans

| | Some while ago I modified GHC to have an extra runtime | | flag to let you change this behaviour. The effect was | | that 3 turns into simply (fromInt 3), and the | | "fromInt" means "whatever fromInt is in scope". | | Hmmm... so how about: | | foo fromInt = 3 | | Would this translate to: | | foo f = f 3 This exactly what will happen. But you are right to say that it is perhaps not what you want. Another alternative would be: "3" turns into "Prelude.fromInt 3", where "Prelude.fromInt" means "whatever Prelude.fromInt is in scope". So then you'd have to say import Prelude () import MyPrelude as Prelude (as Malcolm and Marcin suggested). Maybe that's a good plan; it's a little more heavyweight. [Incidentally, if this is nhc's behaviour, it's not H98. The Report (tries to) stress that you get the "fromInt from the actual standard Prelude" regardless of what is in scope. That's why I'm not going to make it the default behaviour.] Yet another possibility would to be say you get "the unqualified fromInt that's in scope at top level". But that seems worse. Re Bools, Koen and Marcin write (respectively) | | [...] guarantee that (if otherwise e1 e2) = e1. | | I do not understand this. "otherwise" is simply a function | name, that can be used, redefined or hidden, by anyone. It | is not used in any desugaring. Why change that behaviour? | > So much for numerics. It's much less obvious what to do | about booleans. | | IMHO a natural generalization (not necessarily useful) is to follow | the definition of the 'if' syntactic sugar literally. 'if' expands | to the appropriate 'case'. So Prelude.True and Prelude.False must be | defined, and they must have the same type (otherwise we get a type | error each time we use 'if'). This would allow even | data FancyBool a = True | False | DontKnow a The point is that there must be a *defined* desugaring. The desugaring in the report defines the behaviour, but the compiler is free to do differently. If one is to be free to rebind types, the desugaring must be fully defined. Marcin suggests that 'if' is just syntactic sugar. But that would be a disaster if the new Bool type didn't have constructors True and False. For example, maybe Bool becomes a function: type Bool = forall b. b -> b -> b No constructor 'True'! Here I think the right thing is to say that desugaring for boolean constructs uses a function 'if' assumed to have type if :: forall b. Bool -> b -> b -> b Now the programmer can define both Bool and if, and the compiler will be happy. My point is this: there is some *design* to do here. It's not obvious what the design should be. But if anyone feels inclined to do the design (in consultation with the community of course) then I'd be inclined to implement it in GHC. (Though I'm not writing a blank cheque!) Decoupling the prelude is a desirable goal. Simon

Fri, 16 Feb 2001 04:14:24 -0800, Simon Peyton-Jones
[Incidentally, if this is nhc's behaviour, it's not H98. The Report (tries to) stress that you get the "fromInt from the actual standard Prelude" regardless of what is in scope. That's why I'm not going to make it the default behaviour.]
But is mere -fglasgow-exts enough to enable it? BTW: fromInt is not H98. However when a compiler uses fromInt instead of fromInteger where the number fits, with a suitable default method for fromInt which is not exported from Prelude, then no program can tell the difference, so it's OK. Unfortunately integer literals cannot expand to Prelude.fromInt, because Prelude does not export fromInt! Currently ghc extension flags can have no effect on module imports, so if fromInt is not visible in standard mode, it will not visible in extended mode either. In such case these two extensions (Prelude substitution and using fromInt for integer literals) are incompatible.
Marcin suggests that 'if' is just syntactic sugar. But that would be a disaster if the new Bool type didn't have constructors True and False.
Correction: it would be a disaster when there are no Prelude.True and Prelude.False constructors of the same type. It needs not to be called Bool if the desugaring rule does not say so.
Here I think the right thing is to say that desugaring for boolean constructs uses a function 'if' assumed to have type if :: forall b. Bool -> b -> b -> b
What if somebody wants to make 'if' overloaded on more types than some constant type called Bool? class Condition a where if :: a -> b -> b -> b Generally I don't feel the need of allowing to replace if, Bool and everything else with custom definitions, especially when there is no single obvious way. -- __("< Marcin Kowalczyk * qrczak@knm.org.pl http://qrczak.ids.net.pl/ \__/ ^^ SYGNATURA ZASTÊPCZA QRCZAK

On Fri, Feb 16, 2001 at 05:13:10PM +0000, Marcin 'Qrczak' Kowalczyk wrote:
Fri, 16 Feb 2001 04:14:24 -0800, Simon Peyton-Jones
pisze: Here I think the right thing is to say that desugaring for boolean constructs uses a function 'if' assumed to have type if :: forall b. Bool -> b -> b -> b
What if somebody wants to make 'if' overloaded on more types than some constant type called Bool?
class Condition a where if :: a -> b -> b -> b
(Note that Hawk does almost exactly this.)
Generally I don't feel the need of allowing to replace if, Bool and everything else with custom definitions, especially when there is no single obvious way.
Why not just let if x then y else z be syntactic sugar for Prelude.ifThenElse x y z when some flag is given? That allows a Prelude hacker to do whatever she wants, from the standard ifThenElse :: Bool -> x -> x -> x ifThenElse True x _ = x ifThenElse True _ y = y to something like class (Boolean a) => Condition a b where ifThenElse :: a -> b -> b -> b ("if" is a keyword, so cannot be used as a function name. Hawk uses "mux" for this operation.) Compilers are good enough to inline the standard definition (and compile it away when appropriate), right? Pattern guards can be turned into "ifThenElse" as specified in section 3.17.3 of the Haskell Report. Or maybe there should be a separate function "evalGuard", which is ordinarily of type evalGuard :: [(Bool, a)] -> a -> a (taking the list of guards and RHS, together with the default case). It's less clear that compilers would be able to produce good code in this case. But this would have to be changed: An alternative of the form pat -> exp where decls is treated as shorthand for: pat | True -> exp where decls Best, Dylan Thurston
participants (3)
-
Dylan Thurston
-
qrczak@knm.org.pl
-
Simon Peyton-Jones