2

From Haskell 2010 report, section 5.4. "an instance declaration is in scope if and only if a chain of import declarations leads to the module containing the instance declaration. ".

I indeed checked with a simple program and it does bring in scope instances recursively, that is even if they are not directly in the imported module.

Why is that recursive behavior desirable/necessary? Would it be so bad if it only brought in scope all the instances contained only inside the target module? (I don't want to import one specific instance). Would that really increase the number of imports so much? Are there some fundamental/compilation/historical reasons it cannot be this way?

My current impression is that a big part of the hostility regarding orphan instances might be based on that premiss, as a bad risk is that you unintentionally import an undesired orphan from some deeply buried module.

jam
  • 803
  • 5
  • 14
  • Since you can not specify to "exclude" instances, if you import them, then these are defined in the module, and thus you "export" these as well, since you export all that is in scope. – Willem Van Onsem May 29 '20 at 20:14
  • @Willem Van Onsem. Couldn't there be a separation of the instance import scope, from the definition scope? That sounds like an implementation detail. Maybe its just how GHC was coded. But i'm not sure why it was coded like that. – jam May 29 '20 at 20:16
  • that could, but it would be a bit inconsistent with the rest. For example you can also import types, functions, data constructors, typeclasses, etc. from one module, and re-export these. That happens often. Why treat instances differently than functions? – Willem Van Onsem May 29 '20 at 20:16
  • 1
    Well I think they are treated differently. Instances are invisibly imported/exported, whereas classes and functions have to be explictly in the export list. – jam May 29 '20 at 20:22
  • no, if you do not write an export list, then it is all exported. You can export with an export list that includes everything, or with `hiding` in which case you export all except the items in the `hiding` list. Furthermore the main problem on how to export/import instances is, how to denote these? How would you export an instance? With `instance Foo Bar`? What if it is an instance `instance Foo a => Foo [a]`? What if you only want to import export `Foo [[Char]]`, and not `Foo [Char]`, etc.? – Willem Van Onsem May 29 '20 at 20:24
  • I am clarifying a bit, I don't want to import specific instances, I want to import all of them but only those inside the target module, just not recursively. – jam May 29 '20 at 20:35
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/214941/discussion-between-jam-and-willem-van-onsem). – jam May 29 '20 at 20:39
  • 4
    tl;dr: Because coherence is important. – Joseph Sible-Reinstate Monica May 29 '20 at 21:08
  • Yes the answer to "why no specific instance import" https://stackoverflow.com/questions/8728596/explicitly-import-instances looks like it applies also to my question "why recursive imports". I'm not sure if that would count as duplicate though, as my question was slightly different. – jam May 30 '20 at 09:54
  • 2
    Voted to reopen. This question is not really opinion-based; its answer follows from a fundamental, well-documented aspect of how typeclasses work in Haskell. – duplode May 30 '20 at 13:17
  • @duplode I totally agree. I think people who closed it were distracted and just read some words like "desirable" and reacted too promptly. I was not launching a debate, but rather asking what is the historically dominant view over this. – jam May 30 '20 at 14:08

1 Answers1

4

I believe ehird's answer from here Explicitly import instances also provides an answer to this question. If instances were not imported in a recursive fashion, then it would be possible to achieve the same effect as in their example.

A function could be created with a given Ord instance in some Bar.hs module importing some Data.Ord module. Then that function might be used in some other Baz.hs module which defines its own Ord instance, and doesn't import Data.Ord. Thus it would create undesirable incoherence. I initially thought this problem was just applying to specific instance imports, but it also applies in this case.

It is necessary to avoid that problem that every instance that is imported and in scope of some module, is automatically reexported to any other module, which means transitivity is unavoidable.

jam
  • 803
  • 5
  • 14