在 Haskell 中打印 Pascal 的三角形
Printing Pascal's triangle in Haskell
刚开始学习Haskell,一直在网上做几道题。大多数时候,我可以找出解决方案,但无法以预期的输出格式打印出来。
例如,我尝试编写一个 Pascal 的三角形程序。我发现了如何将帕斯卡三角生成为整数列表的列表,但我不知道如何打印它。
这是我的代码。
import Data.List
pascal n = map liner [0..n]
where liner x = map (comb x) [0..x]
comb n 0 = 1
comb 0 r = 0
comb n r = comb (n-1) (r-1) * n `div` r
main = do
order <- getLine
let output = pascal . (read :: String -> Int) $ order
print output
目前,输出类似于
[[1],[1,1],[1,2,1],[1,3,3,1]...
我要打印成
的形式
1
1 1
1 2 1
1 3 3 1
...
我该怎么做?我曾尝试使用 mapM_ 或插入“”之类的东西,但没有成功。我还不喜欢 monad,所以我不明白 mapM 是如何工作的。
有几种不同的方法可以做到这一点,但最直接的 (IMO) 是以下方法。
putStrLn $ intercalate "\n" $ map (intercalate " " . map show) output
这首先将列表中的所有数字转换为字符串(使用 show
)。然后它将最里面的列表转换为字符串,其中每个元素由空格分隔(使用 intercalate " "
)。然后它将 outermost 列表转换为字符串,其中每个元素由 newline 分隔(使用 intercalate "\n"
)。最后,它将结果字符串推送到标准输出。用这个替换你的 main
的最后一行,它应该做你想要的。
编辑:
正如 Yakym 在他的回答中提到的,intercalate " "
和 intercalate "\n"
可以替换为 unwords
和 unlines
,使上面的代码更加简洁(它也消除了对导入 Data.List
).
putStr $ unlines $ map (unwords . map show) output
我将 putStrLn
更改为 putStr
因为 unlines
会自动在输出的末尾添加一个换行符。
还有像 unlines
和 unwords
这样的函数可以在字符串列表上进行自然插入。
pascal :: [[Int]]
pascal = iterate (\row -> zipWith (+) ([0] ++ row) (row ++ [0])) [1]
printPascal :: [[Int]] -> IO ()
printPascal = mapM_ (putStrLn . unwords . map show)
--*Main> printPascal $ take 10 pascal
--1
--1 1
--1 2 1
--1 3 3 1
--1 4 6 4 1
--1 5 10 10 5 1
--1 6 15 20 15 6 1
--1 7 21 35 35 21 7 1
--1 8 28 56 70 56 28 8 1
--1 9 36 84 126 126 84 36 9 1
刚开始学习Haskell,一直在网上做几道题。大多数时候,我可以找出解决方案,但无法以预期的输出格式打印出来。
例如,我尝试编写一个 Pascal 的三角形程序。我发现了如何将帕斯卡三角生成为整数列表的列表,但我不知道如何打印它。
这是我的代码。
import Data.List
pascal n = map liner [0..n]
where liner x = map (comb x) [0..x]
comb n 0 = 1
comb 0 r = 0
comb n r = comb (n-1) (r-1) * n `div` r
main = do
order <- getLine
let output = pascal . (read :: String -> Int) $ order
print output
目前,输出类似于
[[1],[1,1],[1,2,1],[1,3,3,1]...
我要打印成
的形式1
1 1
1 2 1
1 3 3 1
...
我该怎么做?我曾尝试使用 mapM_ 或插入“”之类的东西,但没有成功。我还不喜欢 monad,所以我不明白 mapM 是如何工作的。
有几种不同的方法可以做到这一点,但最直接的 (IMO) 是以下方法。
putStrLn $ intercalate "\n" $ map (intercalate " " . map show) output
这首先将列表中的所有数字转换为字符串(使用 show
)。然后它将最里面的列表转换为字符串,其中每个元素由空格分隔(使用 intercalate " "
)。然后它将 outermost 列表转换为字符串,其中每个元素由 newline 分隔(使用 intercalate "\n"
)。最后,它将结果字符串推送到标准输出。用这个替换你的 main
的最后一行,它应该做你想要的。
编辑:
正如 Yakym 在他的回答中提到的,intercalate " "
和 intercalate "\n"
可以替换为 unwords
和 unlines
,使上面的代码更加简洁(它也消除了对导入 Data.List
).
putStr $ unlines $ map (unwords . map show) output
我将 putStrLn
更改为 putStr
因为 unlines
会自动在输出的末尾添加一个换行符。
还有像 unlines
和 unwords
这样的函数可以在字符串列表上进行自然插入。
pascal :: [[Int]]
pascal = iterate (\row -> zipWith (+) ([0] ++ row) (row ++ [0])) [1]
printPascal :: [[Int]] -> IO ()
printPascal = mapM_ (putStrLn . unwords . map show)
--*Main> printPascal $ take 10 pascal
--1
--1 1
--1 2 1
--1 3 3 1
--1 4 6 4 1
--1 5 10 10 5 1
--1 6 15 20 15 6 1
--1 7 21 35 35 21 7 1
--1 8 28 56 70 56 28 8 1
--1 9 36 84 126 126 84 36 9 1