2016-09-17 66 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 "+")