3

当我为 PhisicalCell 数据类型手动编写一个简单的显示实例时,程序会占用所有空间。在导出他自己的 Show 版本时,不会发生这种情况。为什么?

这是我正在编写的代码的精简版本:

import Data.Array

type Dimensions = (Int, Int)
type Position = (Int, Int)
data PipeType = Vertical | Horizontal | UpLeft | UpRight | DownLeft | DownRight deriving (Show)

data PhisicalCell = AirCell
                  | PipeCell PipeType
                  | DeathCell
                  | RecipientCell Object
                  -- deriving (Show) SEE THE PROBLEM BELOW  

data Object = Pipe { pipeType :: PipeType  -- tipo di tubo
                   , position :: Position  -- posizione del tubo
                   , movable  :: Bool      -- se posso muoverlo
                   }
            | Bowl { position   :: Position                 -- posizione dell'angolo in alto a sinistra
                   , dimensions :: Dimensions               -- dimensioni (orizzontale, verticale)
                   , waterMax   :: Int                      -- quanta acqua puo' contenere al massimo
                   , waterStart :: Int                      -- con quanta acqua parte 
                   , hatch      :: Maybe Position           -- un eventuale casella di sbocco
                   , sourceIn   :: [Position]               -- posti da cui l'acqua entra
                   , movable    :: Bool                     -- se posso muoverlo
                   }
            | Death
            deriving (Show)

data Level = Level Dimensions [Object]
type LevelTable = Array Dimensions PhisicalCell

-- HERE IS THE PROBLEM -- 
instance Show PhisicalCell where
show AirCell = " "
show (PipeCell _) = "P"
show DeathCell = "X"
show (RecipientCell _) = "U"

both :: (a -> b) -> (a,a) -> (b,b)
both f (a,b) = (f a, f b)

levelTable :: Level -> LevelTable
levelTable (Level dim _) = initial
  where initial = array ((0,0), both (+1) dim) $
                    [((x,y), AirCell) | x <- [1..fst dim], y <- [1..snd dim] ]
                    ++ [((x,y), DeathCell) | x <- [0..fst dim + 1], y <- [0, snd dim + 1]]
                    ++ [((x,y), DeathCell) | x <- [0, fst dim + 1], y <- [0..snd dim + 1]]

main = print $ levelTable (Level (8,12) []) 
4

2 回答 2

7

Show类型类具有相互引用的默认实现:

class  Show a  where
    -- | Convert a value to a readable 'String'.
    --
    -- 'showsPrec' should satisfy the law
    -- ...
    ...
    showsPrec _ x s = show x ++ s
    show x          = shows x ""
    showList ls   s = showList__ shows ls s

...

shows           :: (Show a) => a -> ShowS
shows           =  showsPrec 0

因此,如果您声明一个Show实例而不定义任何方法

instance Show where

nextNewFunction :: Bla
...

GHC 会很高兴地编译所有默认的,所以不会有任何错误。但是,一旦您尝试使用它们中的任何一个,您就会陷入与您的Objects...一样致命的循环中,并且相互递归最终将破坏堆栈。

现在,您的代码看起来不像有这样一个空instance Show声明,但实际上您确实有:由于缩进错误,show您在那里定义的 被识别为一个新的免费顶级函数,它恰好具有同名GHC.Show.show。你可以添加

show :: PhisicalCell -> String

到您的文件并获得与现在相同的结果。

于 2013-09-19T12:07:43.723 回答
3

问题实际上在于 Sassa NF 指出的间距。当我缩进节目时,它可以工作(当我不缩进时,我得到堆栈溢出)。如果没有缩进,您将定义一个从未使用过的顶级show函数,并且showShow实例的函数PhisicalCell有一个未定义的show函数,这会导致问题。

于 2013-09-19T12:06:24.547 回答