2016-09-17 158 views
0

我正在寫一個函數'printLine',給出一個int列表 - 返回一個包含水平線的字符串。該行的長度應該是整數列表的最大值。例如:Haskell打印水平線

printLine [1, 3, 4, 0] 

應該返回:

+----+----+----+----+ 

(請注意,長度由連字符的數量決定,而不是 '+' - 標誌應該始終有5 '+' - 。招牌)

我已經寫了下面的代碼:

printLine :: [Int] -> String 
printLine widthList = concat $ concat $ foldr (:) [["+"]] boundList 
where boundList = replicate 4 ("+" : hyphenList) 
     hyphenList = replicate max "-" 
     max = maximum widthList 

的代碼工作正常,但是,我覺得我已經過度複雜這個功能。例如,我在函數中使用了'concat'兩次。是否有一種「更清潔」的方式去解決這個問題?

回答

3

部分。你很可能很快就會重新使用這個功能。更重要的是,數字4甚至可能是字符'+'和' - '都是「神奇數字」。

因此第一步可能是將功能融入了更多可重複使用的一個

-- | renamed from "printLine" because "print" has a connotation of I/O in Haskell 
separator :: Int -> String 
separator = repeatedLine 4 

repeatedLine :: Int -> Int -> String 
repeatedLine reps segmentWidth = ... 

即使你從來沒有重複使用的功能,4號現在有標識其用途的名稱(reps)。

關於核心功能。你的折扣是reverse["+"]:。反轉是必要的,因爲boundList在開頭追加'+'。這是一個不錯的優化,但它使組合更加複雜。不過,你這樣做,似乎你有所有這些細節處理。但是還有另一種觀點:從無限開始。所以你已經有了

where segment = '+':replicate segmentWidth '-' 

現在你想重複一遍。最簡單的方法是使用cycle segment,這會產生無限的分段列表。現在你所要做的就是採用正確的前綴 - 將所有的複雜性轉化爲幾個數學運算。

repeatedLine :: Int -> Int -> String 
repeatedLine reps segmentWidth = take (1+reps*(segmentWidth+1)) $ cycle segment 
    where segment = '+':replicate segmentWidth '-' 

獎勵:您現在擁有最少的迭代次數。

0

一些言論:

  • hyphenList = replicate max "-""-"是一個字符串,因此hyphenList將字符串列表。如果你用'-'來代替它會更簡單。這將使hyphenList成爲一個字符串,這將幫助您擺脫concat之一。
  • 我將重命名變量max,因爲Prelude中已經定義了一個名爲max的函數。
  • 您可以使用Data.List中的intercalate函數來簡化摺疊和其他連接。
  • intercalate不會在生成的字符串的開頭和結尾添加分隔符,因此必須手動添加它們。

所以把他們放在一起你會得到:因爲函數試圖做太多一次可能發生的併發症

printLine :: [Int] -> String 
printLine widthList = "+" ++ intercalate "+" boundList ++ "+" 
    where boundList = replicate 4 hyphenList 
     hyphenList = replicate m '-' 
     m = maximum widthList 
+1

你錯過了在開始和結束加號 - 你會得到他們,如果你做了一輪嵌入其他的方式,比如'插入(複製4' - ')(複製5「+」)' –

+0

@DavidFletcher這是一個好主意。我以不同的方式解決了這個問題,以儘可能地接近OP。 – redneb

1

@大衛弗萊徹的評論導致了很好的解決方案:

printLine :: [Int] -> String 
printLine xs = intercalate (replicate (maximum xs) '-') (replicate 5 "+")