Why each of them displays a show, but maybe not?

The documentation of Either and Maybe indicates that they have instances of Show .

Either defined as getting a Show , simply:

 data Either ab = Left a | Right b deriving (Eq, Ord, Read, Show, Typeable) 

However, Maybe does not:

 data Maybe a = Nothing | Just a deriving (Eq, Ord) 

Since they are part of the base and are so similar, why not Maybe display the Show directly?

Another question may also be, where does he get his copy of Show ?

+6
source share
2 answers

An instance for Maybe is explicitly defined in GHC.Show , as well as instances for a whole group of other common types, such as tuples. You can find out where the instance was defined using the command :i in ghci :

 Prelude> :i Maybe data Maybe a = Nothing | Just a -- Defined in 'Data.Maybe' instance Eq a => Eq (Maybe a) -- Defined in 'Data.Maybe' instance Monad Maybe -- Defined in 'Data.Maybe' instance Functor Maybe -- Defined in 'Data.Maybe' instance Ord a => Ord (Maybe a) -- Defined in 'Data.Maybe' instance Read a => Read (Maybe a) -- Defined in 'GHC.Read' instance Show a => Show (Maybe a) -- Defined in 'GHC.Show' 

I don’t know why they explicitly defined the instance or placed it in GHC.Show instead of Data.Maybe - as far as I can tell, it can be transferred to Data.Maybe and / or to the derivative. I assume that they did not want Data.Maybe depend on anything other than GHC.Base (as it is now), presumably because it was used in some other core modules.

+10
source

AFAIK tuples are not defined anywhere, therefore, to avoid the appearance of orphan instances [1], Show instances for tuples must be defined in GHC.Show [2]. When implementing these instances, foldr1 used:

 show_tuple :: [ShowS] -> ShowS show_tuple ss = showChar '(' . foldr1 (\sr -> s . showChar ',' . r) ss . showChar ')' 

therefore GHC.Show imports GHC.List where this function is defined. GHC.List, in turn, defines a lookup that is in the Maybe monad (I think the good old Haskell 98 monomorphism algorithm). Thus, GHC.List imports the data. May be. To define an instance of Show , Data.Maybe will need to import GHC.Show (directly or indirectly), which will make the entire sequence GHC.Show β†’ GHC.List β†’ Data.Maybe β†’ GHC.Show a circular dependency. GHC does not support circular dependencies very well (not that they are easy to maintain!), So the base really works to avoid them.

[1] An orphan instance is one that is defined in a different module than the class and type involved in the instance. Formally, Haskell requires that instance lookup be performed in any module directly or indirectly imported by the compiled module; but for non-orphaned instances, the GHC can short-circuit this and just look in two places. For orphaned instances, it must track each orphan instance in the module, and then keep track of those instances being re-mapped by each module that imports them, which is more expensive (and means that it must support a contextual environment with potentially many instances that even do not apply to the current module, because it does not actually import these classes or types). Therefore, it is good practice to avoid the occurrence of orphan cases for this reason.

A little more philosophical, orphan instances are a really good way to get in your program two conflicting instances of the same type / type, which, since they are both β€œvisible” in your Main module, means that they are conflicting. Thus, the function of the language itself is elegant.

[2] IIRC GHC provides only Show instances up to a (relatively small) fixed number of tuple components, which does not quite meet the requirements of Haskell 98, but is good enough for any practical programming need. (Seriously, don't use tuples with more than three elements anyway; you'll forget what certain components mean). I do not know if the standard has been updated to bring the GHC into conformity in the last few years or not.

+4
source

Source: https://habr.com/ru/post/980674/


All Articles