我有一些类型定义了自定义Show
实例。它们的结构如下:
data TopLevel = TopLevel SndLevel
data SndLevel = SndLevel Int
instance Show SndLevel where
show (SndLevel i) = "SndLevel: \n\t" ++ (show i)
我的Show
的{{1}}实例生成的字符串看起来不错,当它们出现在我的输出中时如下所示:
SndLevel
我想为SndLevel:
5
创建一个Show
实例,该实例会导致topLevel
在打印到终端时看起来像这样:
TopLevel (SndLevel 5)
我希望找到Haskell内置的函数,该函数可以在字符串的开头以及该字符串中TopLevel
SndLevel
5
出现的每个位置之前添加"\t"
。
我发现的最佳解决方案将遵循this帖子中的答案。在这种情况下,我将"\n"
替换为"\n"
。
我假设我不是第一个需要在Haskell中使用Show实例来按层次组织数据的人,所以我想知道是否还有一种更惯用的方式来完成此任务。我的问题有更好的解决方案吗?
p.s:我意识到对于我上面使用的示例数据类型而言,这种打印不是最好的。我要为其编写实例的实际数据类型是产品类型,因此当它们延伸到一行时,它们的读取效果不佳。考虑到这一点,如果有一种流行的方法来解决此类问题而无需使用换行符和制表符,那也可以解决我的问题。
答案 0 :(得分:11)
我们可以通过使用lines :: String -> [String]
和unlines :: [String] -> String
从String
移动到String
列表并返回来解决此问题。
在这两者之间,我们可以使用map :: (a -> b) -> [a] -> [b]
在所有行之前添加一个标签(例如String
是Char
的列表),例如:
indent :: String -> String
indent = unlines . map ('\t' :) . lines
例如:
Prelude> indent (show (SndLevel 5))
"\tSndLevel: \n\t\t5\n"
我们可以在Show
和SndLevel
的{{1}}定义中使用它,例如:
TopLevel
因此,这给了我们
instance Show SndLevel where
show (SndLevel n) = "SndLevel:" ++ '\n' : indent (show n)
instance Show TopLevel where
show (TopLevel n) = "TopLevel:" ++ '\n' : indent (show n)
话虽这么说,Prelude> print (TopLevel (SndLevel 5))
TopLevel:
SndLevel:
5
通常用于显示对象的表示形式,该对象通常可以“注入”到编译器/解释器中。使用缩进的想法一点也不坏,但是也许为此定义自己的类型类是有意义的。您可以使用传递和更新的参数来跟踪缩进级别,从而提高该类型类的效率。
此外,还有几个"pretty printing" libraries [Reddit]可以很好地打印对象的结构。因此,与其“ 发明轮子”,不如使用Reddit页面上列出的软件包之一。