Haskell:收到一个列表并多次迭代

时间:2016-08-08 06:54:47

标签: haskell

我正试图在屏幕上画一些东西。

我的函数接收一个int by参数列表(例如[0,0,0,5,5,5,3,3,3,2,4,4,0])并且我要迭代几个来自最大数字的时间([0,0,0,5,5,5,3,3,3,2,4,4,0]) - > 5)直到0

在每次迭代中,我都要检查整个列表,并生成一个String(连接“”,“ - ”和“\ n”)。编写结果假设是这样的:

   ***
   ***    **
   ****** **
   *********
   *********
-------------

我的功能是:

generateSTR (x:xs) = daux (x:xs) (maximum (x:xs)) (x:xs) ""
  where daux (h:hs) mh (y:ys) strdib
           |  mh /= 0 && length(h:hs) == 0       = daux (y:ys) (mh-1) (y:ys) "\n" ++ strdib
           | mh > h && mh > 0 && (h:hs) /= []    = daux hs mh (y:ys) "" ++ strdib
           | mh <= h && mh > 0 && (h:hs) /= []   = daux hs mh (y:ys) "*" ++ strdib
           | mh == 0 && length(h:hs) > 0         = daux hs mh hs "-" ++ strdib
        daux [] 0 [] strdib = strdib
        daux [] _ _ strdib = strdib

问题在于我只是在抽奖中获得第一行(b是空白“”)。

bbb***bbbbbbb

第一行是好的,但我不知道为什么我的程序会停止。当我试图恢复原始列表(函数中的第三个参数)时,我肯定做错了什么。

第三个参数是假设“保存”原始列表,在使用整个列表后,连接“\ n”并恢复原始列表,继续下一次迭代,直到0。

我做错了什么?

提前谢谢。

1 个答案:

答案 0 :(得分:4)

如果您的代码变得如此毛茸茸以至于无法对其进行调试,那么退一步尝试一种新方法来解决问题是件好事。优选地,一个构建较小的可测试组件。

在这种情况下,您尝试生成一个给定高度列表的垂直条形图。正如您所发现的,这样做是 hard 。但是我们可以轻松生成一个水平条,对吗?这只是n字符的重复*

bar :: Int -> String
bar n = replicate n '*'

-- bar 5 = "*****"

下一个棘手的问题是旋转它以使其垂直。那看起来像Haskell的价值是什么?我们不是一个简单的String,而是一个String列表,每个列表代表一行。因此,如果我们将[replicate n '*']作为单行长度n,我们想要的是replicate n ['*'],或n行长度为1.我们可以直接使用该定义,但事实证明此操作只是转置由函数Data.List.transpose提供的矩阵。

verticalBar :: Int -> [String]
verticalBar n = transpose [bar n]

-- verticalBar 5 = ["*","*","*","*","*"]

这应该指出我们如何将水平条列表转换为垂直图形。

transpose . map bar

但这不是很正确,因为我们丢失了一些元素而且图表看起来是颠倒的!我们需要填充每一行,以便在我们转置它之前,我们的水平布局图形不会很粗糙。

graph :: [Int] -> String
graph heights = unlines . transpose . map draw $ heights
  where
    maxHeight = maximum heights
    draw height = replicate (maxHeight - height) ' ' ++ replicate height '*' ++ "-"

现在我们有了图表!

λ putStrLn $ graph [0,0,0,5,5,5,3,3,3,2,4,4,0]
   ***
   ***    **
   ****** **
   *********
   *********
-------------