如何在单个函数中执行多个语句?

时间:2017-03-26 23:00:20

标签: haskell recursion functional-programming

我正在学习Haskell,而且我必须打印一个Snakes and Ladders游戏。开始时,我正在尝试打印电路板,这就是我所做的。

import Data.List
aRow :: Int -> String
aRow n = "+" ++ take (4*n) (intercalate "" (repeat "---+")) ++ "\n|" ++      take (4*n) (intercalate "" (repeat "   |")) ++ "\n"

board :: Int -> Int -> IO()
board 1 y = putStrLn (aRow y)

我想要另一个董事会实例,它需要参数x和y

board x y = putStrLn (aRow y)
            board (x-1) y

我知道我不能只调用这样的多个语句,但是任何人都可以提供一些有关我如何能够接受这一点的见解吗?我想用参数'y'调用aRow并执行'x'次。

感谢。

另外:当我拨打电话板1时,我将其作为输出:     板1 5
    + - + - + - + - + - +
    | | | | | |

3 个答案:

答案 0 :(得分:7)

我认为最干净的方法是创建电路板而不进行任何IO,然后最后只使用IO将其打印出来。

您可以使用concatreplicate来实现此目标:

board :: Int -> Int -> String
board x y = concat (replicate y (aRow x))

你可能在底部错过了一条线,但我会让你弄清楚这一点!

顺便说一下,take (4*n) (intercalate "" (repeat "---+"))concat (replicate n "---+")相同,因此您可以将aRow写为:

aRow :: Int -> String
aRow n = '+' : concat (replicate n "---+")
      ++ "\n|" ++ concat (replicate n "   |")
      ++ "\n"

修改:我会使用unlines :: [String] -> String在多行上连接多个String

aRow :: Int -> String
aRow n = unlines
  [ '+' : concat (replicate n "---+")
  , '|' : concat (replicate n "   |")
  ]

答案 1 :(得分:2)

因此,您希望执行IO (),然后执行另一个IO ()操作。他们一起也应该是IO ()。因此,您正在寻找具有签名IO () -> IO () -> IO ()的组合子。你可以ask Hoogle about this ...亲爱的,这会产生很多无关紧要的结果。但也the right one, namely

(>>) :: Monad m => m a -> m b -> m b

您的IO () -> IO () -> IO ()是此签名的特例,通过设置m ~ IOa ~ b ~ ()获得。所以,你可以写

board x y = putStrLn (aRow y)
         >> board (x-1) y

因为这些 monadic排序运算符经常在Haskell中使用,所以它具有特殊的语法 - 糖语法,即

board x y = do
    putStrLn (aRow y)
    board (x-1) y

好的,这样可行,但它并不是真正的惯用语。带有“计数器变量”x的手动递归“循环”很笨拙,而且容易出错(你需要获得正确的初始,终止和步进条件)。实际上,您所做的就是连续执行x次行动。所以你真的对Int -> IO () -> IO ()感兴趣。再次ask Hoogle;这次the right result提前了一点......

replicateM_ :: Applicative m => Int -> m a -> m ()

所以

board :: Int -> Int -> IO ()
board x y = replicateM_ x $ putStrLn (aRow y)

更好的是,正如Boomerang所言,完全是为了避免IO循环。

答案 2 :(得分:2)

你只需要对两个monadic函数进行排序:

board x y = putStrLn (aRow y) >> board (x - 1) y

或使用do表示法

board x y = do
    putStrLn (aRow y)
    board (x - 1) y

请注意x == 0是一个更自然的基础案例:

board 0 y = return ()
board x y = do
   putStrLn (aRow y)
   board (x - 1) (aRow y)

尽管如此,请参阅Boomerang的答案,了解更为惯用的写作方式。