缩进字符串中的所有行

时间:2019-05-20 20:48:55

标签: string haskell

我有一些类型定义了自定义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:我意识到对于我上面使用的示例数据类型而言,这种打印不是最好的。我要为其编写实例的实际数据类型是产品类型,因此当它们延伸到一行时,它们的读取效果不佳。考虑到这一点,如果有一种流行的方法来解决此类问题而无需使用换行符和制表符,那也可以解决我的问题。

1 个答案:

答案 0 :(得分:11)

我们可以通过使用lines :: String -> [String]unlines :: [String] -> StringString移动到String列表并返回来解决此问题。

在这两者之间,我们可以使用map :: (a -> b) -> [a] -> [b]在所有行之前添加一个标签(例如StringChar的列表),例如:

indent :: String -> String
indent = unlines . map ('\t' :) . lines

例如:

Prelude> indent (show (SndLevel 5))
"\tSndLevel: \n\t\t5\n"

我们可以在ShowSndLevel的{​​{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页面上列出的软件包之一。