2016-04-27 2 views
2

Я только начал изучать Haskell и делал несколько проблем в Интернете. В большинстве случаев я могу найти решение, но я не могу его распечатать в ожидаемом формате вывода.Печать треугольника Паскаля в Haskell

Например, я попытался выполнить программу треугольника Паскаля. Я узнал, как создать Треугольник Паскаля как список списков Ints, но я не могу понять, как его напечатать.

Вот мой код.

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_ или intercalate "", без везения. Я еще не в монады, поэтому я не понимаю, как работает MapM.

+0

Не нужно понимать монады для этого, действительно. 'f = unlines. map (intercalate "". map show) 'будет выдавать желаемое значение' String' из значения '[[Int]]'; просто передайте результат в 'putStr'. – Jubobs

+3

и 'intercalate" "' просто 'unwords' - вы получаете его с' putStr. unlines. map (unwords. map show) ' – Carsten

+0

Aah beautiful. Я смешивал 'lines' и' unlines' и 'map' все неправильно. Я не использовал 'show' правильный путь. Благодаря! –

ответ

3

Существует несколько различных способов сделать это, но наиболее прямым (IMO) является следующее.

putStrLn $ intercalate "\n" $ map (intercalate " " . map show) output 

Это первые новообращенные все номера в списке в строках (используя show). Затем он преобразует самые внутренние списки в строки, где каждый элемент разделяется пробелами (с использованием intercalate " "). Затем он преобразует список outermost в строку, где каждый элемент разделяется символом (с использованием intercalate "\n"). И, наконец, он выталкивает результирующую строку в stdout. Замените последнюю строку вашего main на это, и она должна делать то, что вы хотите.

EDIT: Как Яким отметил в своем ответе, intercalate " " и intercalate "\n" можно заменить unwords и unlines, что делает код выше немного более кратким (он также устраняет необходимость в импорте Data.List).

putStr $ unlines $ map (unwords . map show) output 

Я изменил putStrLn к putStr потому unlines автоматически добавляет символ новой строки в конце вывода.

2

Существуют также функции, такие как 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 
+2

'[0] ++ строка' может быть упрощена до' 0: row' –

+0

Вы правы; Я заимствовал линию из Haskell wiki https://wiki.haskell.org/Blow_your_mind - я полагаю, что вышеупомянутая версия обусловлена ​​симметрией. –

Смежные вопросы