Haskell 如何在一个函数中执行多个语句?
我正在学习Haskell,为了完成一项任务,我必须打印一个蛇和梯子游戏。开始时,我正在尝试打印电路板,这就是我所做的Haskell 如何在一个函数中执行多个语句?,haskell,recursion,functional-programming,Haskell,Recursion,Functional Programming,我正在学习Haskell,为了完成一项任务,我必须打印一个蛇和梯子游戏。开始时,我正在尝试打印电路板,这就是我所做的 import Data.List aRow :: Int -> String aRow n = "+" ++ take (4*n) (intercalate "" (repeat "---+")) ++ "\n|" ++ take (4*n) (intercalate "" (repeat " |")) ++ "\n" board :: Int ->
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)
我想要另一个board实例,这样它就可以接受参数x和y
board x y = putStrLn (aRow y)
board (x-1) y
我知道我不能像这样调用多个语句,但是有人能提供一些关于我如何处理这些语句的见解吗?我想用参数“y”来调用aRow,然后做“x”次
谢谢
另外:当我调用board 1 y时,我将其作为输出:
董事会1 5
+--+--+--+--+--+
| | | | | | 我认为最干净的方法是在不进行任何IO的情况下创建电路板,然后在最后只使用IO打印出来 您可以使用concat和replicate来实现这一点:
board :: Int -> Int -> String
board x y = concat (replicate y (aRow x))
你可能在底部漏了一行,但我会让你弄清楚的
顺便说一句,取4*n interlate repeat-+与concat replicate n-+相同,因此您可以将aRow写为:
编辑:我将使用unlines::[String]->String来连接多行上的多个字符串:
aRow :: Int -> String
aRow n = unlines
[ '+' : concat (replicate n "---+")
, '|' : concat (replicate n " |")
]
我认为最干净的方法是在不进行任何IO的情况下创建电路板,然后在最后只使用IO打印出来 您可以使用concat和replicate来实现这一点:
board :: Int -> Int -> String
board x y = concat (replicate y (aRow x))
你可能在底部漏了一行,但我会让你弄清楚的
顺便说一句,取4*n interlate repeat-+与concat replicate n-+相同,因此您可以将aRow写为:
编辑:我将使用unlines::[String]->String来连接多行上的多个字符串:
aRow :: Int -> String
aRow n = unlines
[ '+' : concat (replicate n "---+")
, '|' : concat (replicate n " |")
]
因此,您需要执行一个IO,然后执行另一个IO操作。它们一起也应该是一个IO。因此,您正在寻找一个具有签名IO->IO->IO的组合器。你可以。。。哦,天哪,这会产生很多不相关的结果。而且
您的IO->IO->IO是此签名的特例,通过设置m~IO和a~b~获得。所以,你可以写
board x y = putStrLn (aRow y)
>> board (x-1) y
因为这些一元排序运算符在Haskell中经常使用,所以它具有特殊的语法糖语法,即
board x y = do
putStrLn (aRow y)
board (x-1) y
好的,这是可行的,但它不是真正的惯用语。带有“计数器变量”x的手动递归“循环”很麻烦,而且很容易出错。您需要正确地获得初始、终止和步进条件。实际上,你所做的就是连续x次执行同一个动作。所以你真的对Int->IO->IO感兴趣。再一次这一次来得稍微早一点
replicateM_ :: Applicative m => Int -> m a -> m ()
所以
更妙的是,正如回力棒所言,完全避免IO循环。因此您希望执行一个IO,然后执行另一个IO操作。它们一起也应该是一个IO。因此,您正在寻找一个具有签名IO->IO->IO的组合器。你可以。。。哦,天哪,这会产生很多不相关的结果。而且
您的IO->IO->IO是此签名的特例,通过设置m~IO和a~b~获得。所以,你可以写
board x y = putStrLn (aRow y)
>> board (x-1) y
因为这些一元排序运算符在Haskell中经常使用,所以它具有特殊的语法糖语法,即
board x y = do
putStrLn (aRow y)
board (x-1) y
好的,这是可行的,但它不是真正的惯用语。带有“计数器变量”x的手动递归“循环”很麻烦,而且很容易出错。您需要正确地获得初始、终止和步进条件。实际上,你所做的就是连续x次执行同一个动作。所以你真的对Int->IO->IO感兴趣。再一次这一次来得稍微早一点
replicateM_ :: Applicative m => Int -> m a -> m ()
所以
更妙的是,正如回力棒所言,完全避免IO循环。您只需对两个单元函数进行排序:
board x y = putStrLn (aRow y) >> board (x - 1) y
或使用do符号
请注意,x==0表示更自然的基本情况:
board 0 y = return ()
board x y = do
putStrLn (aRow y)
board (x - 1) (aRow y)
请参阅Boomerang的答案,了解编写函数的更惯用方法。您只需对两个一元函数进行排序:
board x y = putStrLn (aRow y) >> board (x - 1) y
或使用do符号
请注意,x==0表示更自然的基本情况:
board 0 y = return ()
board x y = do
putStrLn (aRow y)
board (x - 1) (aRow y)
请参阅Boomerang的答案,了解编写函数的更为惯用的方法。我会找到你,我会拥抱你“排队Liam Neeson voice”。我会找到你,我会拥抱你“排队Liam Neeson voice”。