Haskell 中的列表输出格式?

发布于 2024-11-05 11:18:46 字数 385 浏览 2 评论 0原文

我在尝试在 Haskell 中格式化我自己类型的列表的输出时遇到问题。

我想要这样的东西:

Make  | Model | Years(this is a list)    <- this would be the headers if you like
-------------------
Item1 | Item1 | Item1s,Item1s           
Item2 | Item2 | Item2s,Items2,Items2

^ 这将是从我的 String String [Int] 类型加载的数据。

我该如何在 Haskell 中做到这一点?

I am having trouble trying to format the output a of a list of my own type in Haskell.

I would like something like this:

Make  | Model | Years(this is a list)    <- this would be the headers if you like
-------------------
Item1 | Item1 | Item1s,Item1s           
Item2 | Item2 | Item2s,Items2,Items2

^
This would be the data loaded from my String String [Int] type.

How would I do this in Haskell?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

诗化ㄋ丶相逢 2024-11-12 11:18:46

一般来说,我们使用“漂亮的打印”库来完成漂亮的格式化输出。您应该知道的标准是 Text.PrettyPrint。给定一个数据类型,您可以遍历该类型,构建格式良好的文档。

一个例子:

import Text.PrettyPrint
import Data.List

-- a type for records
data T = T { make  :: String
           , model :: String
           , years :: [Int] }
    deriving Show

-- test data
test =
    [ T "foo" "avenger" [1990, 1992]
    , T "bar" "eagle"   [1980, 1982]
    ]

-- print lists of records: a header, then each row
draw :: [T] -> Doc
draw xs =
    text "Make\t|\tModel\t|\tYear"
   $+$
    vcat (map row xs)
 where
    -- print a row
    row t = foldl1 (<|>) [ text (make t)
                         , text (model t)
                         , foldl1 (<^>) (map int (years t))
                         ]

-- helpers
x <|> y = x <> text "\t|\t" <> y
x <^> y = x <> text "," <+> y

测试:

main = putStrLn (render (draw test))

结果:

Make    |   Model   |   Year
foo     |   avenger |   1990, 1992
bar     |   eagle   |   1980, 1982

快速编写漂亮的打印机的能力是一项非常有用的技能。

Generally, we use "pretty printing" libraries to do nice formatted output. The standard one that you should know is Text.PrettyPrint. Given a data type, you can walk that type, building up a well-formated document.

An example:

import Text.PrettyPrint
import Data.List

-- a type for records
data T = T { make  :: String
           , model :: String
           , years :: [Int] }
    deriving Show

-- test data
test =
    [ T "foo" "avenger" [1990, 1992]
    , T "bar" "eagle"   [1980, 1982]
    ]

-- print lists of records: a header, then each row
draw :: [T] -> Doc
draw xs =
    text "Make\t|\tModel\t|\tYear"
   $+$
    vcat (map row xs)
 where
    -- print a row
    row t = foldl1 (<|>) [ text (make t)
                         , text (model t)
                         , foldl1 (<^>) (map int (years t))
                         ]

-- helpers
x <|> y = x <> text "\t|\t" <> y
x <^> y = x <> text "," <+> y

Testing:

main = putStrLn (render (draw test))

Results in:

Make    |   Model   |   Year
foo     |   avenger |   1990, 1992
bar     |   eagle   |   1980, 1982

The ability to quickly write pretty printers is an incredibly useful skill.

踏雪无痕 2024-11-12 11:18:46

这是一个通用的表生成器。它计算列宽以适合最宽的行。 ColDesc 类型允许您为每列指定标题对齐方式、标题字符串、数据对齐方式以及格式化数据的函数。

import Data.List (transpose, intercalate)

-- a type for records
data T = T { make  :: String
           , model :: String
           , years :: [Int] }
    deriving Show

-- a type for fill functions
type Filler = Int -> String -> String

-- a type for describing table columns
data ColDesc t = ColDesc { colTitleFill :: Filler
                         , colTitle     :: String
                         , colValueFill :: Filler
                         , colValue     :: t -> String
                         }

-- test data
test =
    [ T "foo" "avenger" [1990, 1992]
    , T "bar" "eagle"   [1980, 1982, 1983]
    ]

-- functions that fill a string (s) to a given width (n) by adding pad
-- character (c) to align left, right, or center
fillLeft c n s = s ++ replicate (n - length s) c
fillRight c n s = replicate (n - length s) c ++ s
fillCenter c n s = replicate l c ++ s ++ replicate r c
    where x = n - length s
          l = x `div` 2
          r = x - l

-- functions that fill with spaces
left = fillLeft ' '
right = fillRight ' '
center = fillCenter ' '

-- converts a list of items into a table according to a list
-- of column descriptors
showTable :: [ColDesc t] -> [t] -> String
showTable cs ts =
    let header = map colTitle cs
        rows = [[colValue c t | c <- cs] | t <- ts]
        widths = [maximum $ map length col | col <- transpose $ header : rows]
        separator = intercalate "-+-" [replicate width '-' | width <- widths]
        fillCols fill cols = intercalate " | " [fill c width col | (c, width, col) <- zip3 cs widths cols]
    in
        unlines $ fillCols colTitleFill header : separator : map (fillCols colValueFill) rows

运行:

putStrLn $ showTable [ ColDesc center "Make"  left  make
                     , ColDesc center "Model" left  model
                     , ColDesc center "Year"  right (intercalate ", " . map show . years)
                     ] test

结果:

Make |  Model  |       Year      
-----+---------+-----------------
foo  | avenger |       1990, 1992
bar  | eagle   | 1980, 1982, 1983

Here is a generalized table generator. It calculates the column widths to fit the widest row. The ColDesc type allows you to specify, for each column, the title alignment, the title string, the data alignment, and a function to format the data.

import Data.List (transpose, intercalate)

-- a type for records
data T = T { make  :: String
           , model :: String
           , years :: [Int] }
    deriving Show

-- a type for fill functions
type Filler = Int -> String -> String

-- a type for describing table columns
data ColDesc t = ColDesc { colTitleFill :: Filler
                         , colTitle     :: String
                         , colValueFill :: Filler
                         , colValue     :: t -> String
                         }

-- test data
test =
    [ T "foo" "avenger" [1990, 1992]
    , T "bar" "eagle"   [1980, 1982, 1983]
    ]

-- functions that fill a string (s) to a given width (n) by adding pad
-- character (c) to align left, right, or center
fillLeft c n s = s ++ replicate (n - length s) c
fillRight c n s = replicate (n - length s) c ++ s
fillCenter c n s = replicate l c ++ s ++ replicate r c
    where x = n - length s
          l = x `div` 2
          r = x - l

-- functions that fill with spaces
left = fillLeft ' '
right = fillRight ' '
center = fillCenter ' '

-- converts a list of items into a table according to a list
-- of column descriptors
showTable :: [ColDesc t] -> [t] -> String
showTable cs ts =
    let header = map colTitle cs
        rows = [[colValue c t | c <- cs] | t <- ts]
        widths = [maximum $ map length col | col <- transpose $ header : rows]
        separator = intercalate "-+-" [replicate width '-' | width <- widths]
        fillCols fill cols = intercalate " | " [fill c width col | (c, width, col) <- zip3 cs widths cols]
    in
        unlines $ fillCols colTitleFill header : separator : map (fillCols colValueFill) rows

Running:

putStrLn $ showTable [ ColDesc center "Make"  left  make
                     , ColDesc center "Model" left  model
                     , ColDesc center "Year"  right (intercalate ", " . map show . years)
                     ] test

Results in:

Make |  Model  |       Year      
-----+---------+-----------------
foo  | avenger |       1990, 1992
bar  | eagle   | 1980, 1982, 1983
丢了幸福的猪 2024-11-12 11:18:46

像这样的东西吗?

import Data.List (intercalate)
data Foo = Foo String String [Int]

fooToLine :: Foo -> String
fooToLine (Foo a b cs) = a ++ " | " ++ b ++ " | " ++ intercalate ", " (map show cs)

现在,你可以做

>>> fooToLine (Foo "Hello" "World" [1, 2, 3])
"Hello | World | 1, 2, 3"

Something like this?

import Data.List (intercalate)
data Foo = Foo String String [Int]

fooToLine :: Foo -> String
fooToLine (Foo a b cs) = a ++ " | " ++ b ++ " | " ++ intercalate ", " (map show cs)

Now, you can do

>>> fooToLine (Foo "Hello" "World" [1, 2, 3])
"Hello | World | 1, 2, 3"
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文