Haskell if else 列表推导式

5
我将尝试以正确的方式打印出一个版面,就像这样:

  1   2   3   4   5   6   7   8   9   10  11  12  13  14  15  16  17  18  
 1.   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .         
 2.   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .         
 3.   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .         
 4.   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .         
 5.   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .         
 6.   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .         
 7.   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .         
 8.   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .         
 9.   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .         
10.   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .         
11.   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .         
12.   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .         
13.   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .         
14.   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .         
15.   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .         
16.   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .         
17.   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .         
18.   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .         

我这里有列表推导式。
 ((concat [(""++show i)++"   " | i <- [1..n], i<10])++"\n")

我可以正确获得前9个数字,但当我想在我的推断中加入一个else语句时,问题就出现了。我似乎不知道该怎么做。因此,为了让自己更加清晰,我想用相同的方法处理双位数,但唯一的区别是我希望两个双位数之间只有两个空格而不是三个。


如果i < 10,则为“三个空格”,否则为“两个空格”,而我对 Haskell 还很陌生,所以不知道您所说的 intercalate 是什么意思。我正在尽我所能利用已知的知识。 - ruubel
当你尝试使用 if i<10 then "three spaces" else "two spaces" 会出现什么问题? - Daniel Wagner
我做不到,我需要按照这种方式编写。在列表推导式中编写else语句是否可能? - ruubel
所以表单应该是 [<expr> | <list monad> | <expr> | <list monad>]? - ruubel
@ruubel:不是的,例如 [ if <bool-expr> then <expr> else <expr> | <list-monad>] - Willem Van Onsem
显示剩余2条评论
1个回答

2

列表推导式的左侧接受任何Haskell表达式,因此我们可以在列表推导式的左侧编写if-then-else,并省略右侧的i < 10条件:

concat [(""++show i)++if i < 10 then "   " else "  " | i &lt- [1..n]]++"\n"

对于 n = 15,这将产生:
Prelude> concat [(""++show i)++if i < 10 then "   " else "  " | i <- [1..n]]++"\n"
"1   2   3   4   5   6   7   8   9   10  11  12  13  14  15  \n"

我们也可以在列表推导式的左侧删除""++部分,因为这基本上是一个无操作
concat [show i ++ if i < 10 then "   " else "  " | i &lt- [1..n]] ++ "\n"

上述方法不太优雅:如果i = 123,那么我们仍然会遇到麻烦。我们可以计算show的长度,计算4-l(其中l为长度),并将其作为额外间距添加。例如:
concat [<b>s</b> ++ <b>replicate (4-length s) ' '</b> | i &lt- [1..n], <b>let s = show i</b>] ++ "\n"

还有一些更专业的格式化和连接函数,但是由于这个练习可能是为了熟悉列表,所以我认为这超出了本文的范围。

像@4castle说的那样,我们可以使用例如printf

import Text.Printf(printf)

concatMap (printf "%-4d") [1..n] ++ "\n"

非常感谢,它完美地运行了。它还让我更好地理解了。 - ruubel
你所说的“专用格式化”是指 printf "%-4d" i 吗? - 4castle
@4castle:确实是这样,虽然当然还有更复杂的工具。 - Willem Van Onsem
@4castle:我已经将你的建议添加到答案中了。 - Willem Van Onsem

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接