Welcome toVigges Developer Community-Open, Learning,Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
3.6k views
in Technique[技术] by (71.8m points)

Haskell instance: how could this be some valid code?

While I was writing a small example of the Show instance, I had made an indentation error:

module Main where

data B= B0|B1 

instance Show B where
show B0="0"
show B1="1"


main=print B0

Where, clearly, the working code is:

module Main where

data B= B0|B1 

instance Show B where
    show B0="0"
    show B1="1"


main=print B0

I was expecting to get a compile error on the first one, but instead I could run it and it ended up in:

example.hs: stack overflow

Why does this code even compile?

Also, why is this a runtime error only (which, if stack is unconstrained, fills up your RAM) and not a compilation error?


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

The body of an instance can be empty. You can leave out the where clause:

instance Show B

but you can also include it:

instance Show B where
-- nothing here

This can be useful for type classes that provide default implementations for the methods, perhaps based on generic programming facilities. For example, with the aeson package, the usual way of defining instances to convert to and from JSON is to use generics and empty instances:

{-# LANGUAGE DeriveGeneric #-}

import GHC.Generics

data Person = Person {
      name :: Text
    , age  :: Int
    } deriving (Generic, Show)

-- these empty instances use Generics to provide a default implementation
instance ToJSON Person
instance FromJSON Person

In your program, by leaving out the indentation, you've defined an instance Show B with no method definitions (and -Wall would generate a "missing method" warning telling you that it did not meet the minimal requirements for the instance). The unindented show is providing a new top-level definition for show, unrelated to the show in the Show type class.

You haven't used show explicitly. Instead, you've used it implicitly via print, which always calls the show from the type class, ignoring your top-level definition, so your crashing program is equivalent to:

data B = B0 | B1
instance Show B
main = print B0

This generates a stack overflow because there are default definitions of show and showsPrec that are used when no specific instances are given:

show x = shows x ""
showsPrec _ x s = show x ++ s

which operate together with the top-level function shows (not part of the type class):

shows = showsPrec 0

This works great when at least one of show or showsPrec is defined in the instance, and then the other gets a sensible definition, but if neither is defined, this creates an infinite recursive loop between these three functions.

Also, note that the following program would tell you show was ambiguous which would make it clearer what was going on.

module Main where

data B= B0|B1 

instance Show B where
show B0="0"
show B1="1"

main=putStrLn (show B0) -- instead of print

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to Vigges Developer Community for programmer and developer-Open, Learning and Share
...