我正在写一个函数' printLine' - 给定一个int列表 - 返回一个包含水平线的字符串。此行的长度应为整数列表的最大值。例如:
printLine [1, 3, 4, 0]
应该返回:
+----+----+----+----+
(请注意,长度取决于连字符的数量,而不是' +' -signs。应始终有5' +' -signs。)
我已经写了以下代码:
printLine :: [Int] -> String
printLine widthList = concat $ concat $ foldr (:) [["+"]] boundList
where boundList = replicate 4 ( "+" : hyphenList )
hyphenList = replicate max "-"
max = maximum widthList
代码工作正常,但是,我觉得我过度复杂了这个功能。例如,我使用了#concat'两次功能。是否有清洁剂'怎么回事呢?
答案 0 :(得分: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 '-'
奖励:您现在拥有最少的迭代次数。
答案 1 :(得分:1)
@David Fletcher的评论带来了一个很好的解决方案:
printLine :: [Int] -> String
printLine xs = intercalate (replicate (maximum xs) '-') (replicate 5 "+")
答案 2 :(得分:0)
一些评论:
"-"
中:hyphenList
是一个字符串,因此'-'
将是一个字符串列表。如果您使用hyphenList
代替它会更简单。这会使concat
成为一个字符串,这可以帮助你摆脱max
之一。max
,因为Prelude
中已定义了一个名为Data.List
的函数。intercalate
中的intercalate功能来简化折叠和其他连接。printLine :: [Int] -> String
printLine widthList = "+" ++ intercalate "+" boundList ++ "+"
where boundList = replicate 4 hyphenList
hyphenList = replicate m '-'
m = maximum widthList
不会在生成的字符串的开头和结尾添加分隔符,因此必须手动添加它们。所以把它们放在一起你得到:
node server.js