Replies: 2 comments
-
|
Thanks! I will look at this when I have some time. |
Beta Was this translation helpful? Give feedback.
0 replies
-
|
I've (finally) merged your PR. Thank you! |
Beta Was this translation helpful? Give feedback.
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
-
The practical advantages of the monomorphism restriction can be illustrated, I believe, by the following example:
Running this will produce:
This default behavior can be changed with annotations: so
tb :: forall a . Num a => awill lead to multiple evaluations with MR (which is on by default inghc), whilelet (x :: Int) = ...will allow the sharing ofxwhen MR is off (like inghci). Even though I must confess I find more aesthetically pleasing the second approach, Haskell 2010 decided to go with the first one, apparently because, according to § 6.2 of "Being Lazy With Class", «Hughes argued strongly that it was unacceptable to silently duplicate computation in this way. His argument was motivated by a program he had written that ran exponentially slower than he expected»mhsbehaves differently:It generalizes function, pattern and simple top-level binds. I have reasons to believe this is driven by its architectural design: binds are grouped into strongly connected components, each group is independently type-checked, while the substitution map is reset at each iteration. This way all unification variables for each group can be garbage collected and the memory footprint limited.
One consequence of this design is that, if binds were not generalized, they would have to be immediately defaulted before
tcResetis called, and that would lead to problems, as illustrated by this example:This is a simplified version of what can be found in the package
colour(Data.Colour.CIE.Chromaticity):constant, if not generalized, must be immediately defaulted toInteger(to allow for the SCC memory reset) before checking it at call site inf, which would lead to an unsatisfied constraintInt ~ Integer.Lacking a module-wide substitution map Rule 2 of MR cannot be applied, and the generalization of top-level binds becomes a requirement. This is a concrete illustration:
This will produce:
runghc-9.14 -XNamedDefaults -XExtendedDefaultRules test.hs [Char] -> [Char]But if we change the last line to:
it would produce:
runghc-9.14 -XNamedDefaults -XExtendedDefaultRules test.hs Integer -> [Char] 42mhsinstead produces:mhs -r test.hs [Char] -> [Char] 42mhsgeneralizesmyshowand instantiates it with different meta variables at each call site, defaulting the type at each occurrence.I doubt that implementing a module-wide substitution map in order to avoid multiple evaluation of top-level binds would make sense given the spirit of `mhs. But still I thought it could be useful to point the problem.
Simple non-overloaded local binds
Locally, instead,
mhs, after droppingMonoLocalBinds, generalizes only function binds.So this works:
and this does not:
I created a branch for implementing the generalization of non-overloaded binds:
https://github.com/arossato/MicroHs/tree/monomorphism_restriction
And here the modifications can be seen
I think there are good reasons why this should be allowed:
This seems (or seemed?) to introduce some confusion, though, since it may be difficult to immediately grasp why
let f = idworks whilelet forM = flip mapM, which is overloaded, is rejected. But, I believe, this would be coherent with the Haskell report and possibly complete the "allow generalization for local bindings" entry in theTODO.Beta Was this translation helpful? Give feedback.
All reactions