我有一个sml-nj项目,我想在其中使用列表列表'结构,有" Squares"。我试图递归地将值插入列表列表,但我仍然不知道如何将元素插入到2d列表中。 注意 - 我只能使用' REF',http://smlfamily.org/Basis/list.html#SIG:LIST.app:VAL这些功能。
datatype SquareContent = Mine | Digit of int | Blank;
datatype Square = Revealed of SquareContent | Concealed of SquareContent;
fun createMineSweeperGrid (n:int)
:(Square list list)=
let
fun createMines (rowCounter:int, colCounter:int
, retGame:Square list list):(Square list list) =
if rowCounter=n then
retGame (* finished all rows, should be n lists of size n*)
else
if colCounter=n then (*finished current row, move on*)
createMines (rowCounter+1, 0, mines,retGame)
else
let
val squareToInsert = Concealed(Mine) (* I wish to insert 'squareToInsert'
to retGame[rowCounter][colCounter], it's done dynamically, but I don't know
how to do that *)
in
createMines (rowCounter, colCounter+1, retGame)
end
in
createMines (0,0,[])
end
我可以插入任何类型的Square,它是动态决定的,在这里我只举例说明隐藏的Mine,所以你可以帮助我..帮助..?
答案 0 :(得分:2)
要认识到的重要一点是,在标准ML中,您不会改变现有结构;相反,你创造了新的。 (标准ML通过ref
和它的朋友来支持支持可变结构,但它不是轻易做的事情,我看到你已经 - 正确地 - 排除了它。)< / p>
因此,一般情况下,将某些内容插入链接列表的中间是非常昂贵的:它需要将列表“展开”到您要插入的位置,然后插入值,最后构建所有内容的副本解开了。例如,这是一个在列表的索引x
处插入值i
的函数:
fun insert (x, 0, L) = x :: L
| insert (x, i, h :: t) = h :: insert (x, i - 1, t)
| insert (_, _, nil) = raise Subscript
幸运的是,编写了您的函数,以便不必在已构建的链表的中间插入任何内容;相反,如果我正确理解它正在尝试做什么,它总是将新方块放在第一个列表的开头。所以:
let
val squareToInsert = Concealed(Mine)
val topRow :: rest = retGame
in
createMines (rowCounter, colCounter+1, (squareToInsert::topRow)::rest)
end
请注意,您还需要修复另一个错误,即您实际上从未创建过新行:您有关于“已完成当前行,继续前进”的评论,但之后它只是完全相同,就像它一样仍然在同一行(只是重置数字,好像它已移动到一个新行)。要解决此问题,请在要在顶部添加新行时使用[] :: retGame
,并使用[[]]
代替[]
作为初始板(以便以空行开头) )。