使用Haskell的元素随机网格

Eni*_*rsa 2 random io haskell do-notation io-monad

拥有Haskell的经验绝对为零,我需要提出与该Python等效的代码:

from random import choice, sample

def random_subset():
    return tuple(sample(('N', 'S', 'W', 'E'), choice((1, 2, 3, 4))))

def form_grid(n):
    return [[random_subset() for _ in range(n)] for _ in range(n)]

form_grid(10)
Run Code Online (Sandbox Code Playgroud)

产生这样的事情:

N     ESWN  SNEW  NSE   EWSN  E     ENSW  N     NSWE  WES   
NE    WNS   SWEN  EWN   ENWS  WEN   WS    W     ENSW  NW    
WENS  NWE   SNEW  ES    E     S     ES    SENW  EW    WEN   
NSE   NE    WNE   NEWS  SNE   W     SWNE  NSWE  SNEW  EN    
S     SNW   WNES  S     WESN  E     ES    N     ESN   ES    
SWEN  S     WSNE  NEWS  WESN  E     S     SE    E     N     
NEW   S     NEW   WS    W     EN    N     NWS   E     WENS  
WN    NWE   S     SEW   NESW  EWSN  WENS  ES    NWS   WN    
W     NWE   N     N     ES    E     E     WN    SWNE  NES   
WENS  NWE   NW    WESN  SW    NES   ENWS  SE    N     SWNE 
Run Code Online (Sandbox Code Playgroud)

对于上帝的爱,我无法为Haskell的IO概念(尤其是随机性)所困扰。我能想到的最好的办法是:

N     ESWN  SNEW  NSE   EWSN  E     ENSW  N     NSWE  WES   
NE    WNS   SWEN  EWN   ENWS  WEN   WS    W     ENSW  NW    
WENS  NWE   SNEW  ES    E     S     ES    SENW  EW    WEN   
NSE   NE    WNE   NEWS  SNE   W     SWNE  NSWE  SNEW  EN    
S     SNW   WNES  S     WESN  E     ES    N     ESN   ES    
SWEN  S     WSNE  NEWS  WESN  E     S     SE    E     N     
NEW   S     NEW   WS    W     EN    N     NWS   E     WENS  
WN    NWE   S     SEW   NESW  EWSN  WENS  ES    NWS   WN    
W     NWE   N     N     ES    E     E     WN    SWNE  NES   
WENS  NWE   NW    WESN  SW    NES   ENWS  SE    N     SWNE 
Run Code Online (Sandbox Code Playgroud)

仍然没有做到这一点:

error:
    * Couldn't match expected type `[IO [Char]]'
                  with actual type `IO [Char]'
    * In the expression: randSubset
      In a stmt of a list comprehension: subset <- randSubset
      In the expression:
        [subset | _ <- [0 .. (n - 1)], subset <- randSubset]
   |
12 | formGrid n = [[subset | _ <- [0..(n - 1)], subset <- randSubset] | _ <- [0..(n - 1)]]
   |                                                      ^^^^^^^^^^
Run Code Online (Sandbox Code Playgroud)

快速谷歌搜索并没有太大帮助-我可能没有使用最准确的关键字来解决我遇到的这个问题。进行随机更改并希望达到最佳效果变得很沮丧,但我确实没有时间也没有精力适当地投入Haskell(即使这很遗憾),所以现在,我希望有人能指出我的意思。此代码有误。

Wil*_*sem 5

就像已经说过的错误一样,您的列表理解器具有生成器:

formGrid n = [[subset | _ <- [0..(n - 1)], subset <- randSubset] | _ <- [0..(n - 1)]]
Run Code Online (Sandbox Code Playgroud)

因此,这意味着它期望randSubset是某物的列表,但它不是某物的列表,它是IO某物的列表。因此,您不能使用它。

您使用的函数类型也有些问题[[IO [Char]]],因此使用IO [Char]s 矩阵。

您可能正在寻找replicateM :: Monad m => Int -> m a -> m [a],因此您的程序如下所示:

import Control.Monad(replicateM)

formGrid :: Int -> IO [[[Char]]]
formGrid n = replicateM n (replicateM n randSubset)
Run Code Online (Sandbox Code Playgroud)

例如:

Main> formGrid 3
[["WSNE","WNS","S"],["WN","SN","WEN"],["SEWN","ESN","NESW"]]
Run Code Online (Sandbox Code Playgroud)