刚开始使用Haskell!作为练习,我正在尝试实现的当前问题如下:
我们有n个正方形,打印所有可能的世界配置:
将两个正方形表示为两个字符串,这是n = 2的输出示例。我们有(2 ^ n)·(n + 1)=(2 ^ 2)·(2 + 1)= 12个配置。
[[" W"," "],[" "," W"],[" "," "],
[" W","P"],[" ","PW"],[" ","P"],
["PW"," "],["P"," W"],["P"," "],
["PW","P"],["P","PW"],["P","P"]]
条件(1)易于实施。环顾四周,我找到了一些方法来表达它:
p 0 = [[]]
p n = [x:xs | x <- [" ","P"], xs <- p (n-1)]
或
p n = mapM (\x -> [" ","P"]) [1..n]
或
p n = replicateM n [" ","P"]
我不能声称理解最后两个,但这里是为了完整。
问题:如何添加条件(2)?可以使用列表理解吗? 我不那么好看的新手解决方案涉及这些功能:
insertw :: Int -> [String] -> [String]
insertw n xs
| n < 0 = xs
| n >= lgth = xs
| otherwise = (take (n) xs) ++ [xs!!n++"W"] ++ (drop (n+1) xs)
where lgth = length xs
duplicate :: Int -> [String] -> [[String]]
duplicate i squares
| i > lgth = []
| otherwise = (insertw i squares) : duplicate (i+1) squares
where lgth = length squares
worlds :: Int -> [[String]]
worlds n = concat . map (duplicate 0) . p $ n
答案 0 :(得分:3)
条件2不是列表理解的明显候选者,但是您已经编写的工作代码可以被清理。
0
中lgth
到duplicate
的迭代可以使用map
代替显式递归来完成:
duplicate squares = map (\i -> insertw i squares) [0 .. length squares]
duplicate
不再使用索引参数,concat . map
与concatMap
相同:
worlds = concatMap duplicate . p
如果同时执行drop
和take
,则splitAt
通常是更好的操作。
insertw n xs =
case splitAt n xs of
(as, []) -> as
(as, b : bs) -> as ++ ((b ++ "W") : bs)
请注意,我们也删除了length xs
和xs !! n
操作。
作为练习,可以通过压缩duplicate
列表的inits
和tails
来编写另一个简短的squares
函数。
答案 1 :(得分:0)
对我来说似乎很明显:)。在列表推导中,后面的列表可以依赖于先前列表中生成的值。第二个函数通过在添加wumpus时调用第一个函数来生成集合。
p 0 = [[]]
p n = [[x,' ']:xs | x <- [' ','P'], xs <- p (n-1)]
pw 0 = [[]]
pw n = [[x,w]:xs | w <- [' ','W'], x <- [' ','P'], xs <- if w == 'W' then p (n-1) else pw (n-1)]
它不尽可能干净,但我总是发现列表理解为问题带来了优雅:)。完全值得。