SMLNJ:运营商和;操作数don';t同意[tycon mismtach]-进行列表分配

SMLNJ:运营商和;操作数don';t同意[tycon mismtach]-进行列表分配,sml,smlnj,Sml,Smlnj,我在SMLNJ中编写了以下函数: fun f(id : int, l : int list list) = let val i : int = length(l) - 1 in while i > 0 do ( if (exists(id, List.nth(l, i))) then List.hd(List.nth(l, i)) := 1 else(); i = i - 1 ) end; 收到

我在SMLNJ中编写了以下函数:

fun f(id : int, l : int list list) =
  let
    val i : int = length(l) - 1
  in
    while i > 0 do
    (
      if (exists(id, List.nth(l, i))) then
        List.hd(List.nth(l, i)) := 1
      else();

      i = i - 1
    )
end;
收到的错误如下:

Error operator and operand don't agree [tycon mismatch]
  operator domain: 'Z ref * 'Z
  operand:         int * [int ty]
  in expression:
    List.hd (List.nth (l,i)) := 1
我知道运算符域是函数所期望的,而操作数是所提供的。 我认为这是因为
int
不能分配给
列表
类型。但是,我不清楚
List.hdList.nth(l,I))
将如何导致
int
以外的任何结果


请告知我如何修复此错误以及支持逻辑。

SML/NJ的错误消息并没有非常清楚地说明这一点。如果将此代码放在REPL中,并包含已使用但未定义的函数
contains
,则会出现以下错误:

! Toplevel input:
!         List.hd(List.nth(l, i)) := 1
!                          ^
! Type clash: expression of type
!   int list list
! cannot have type
!   'a ref list list
您的程序失败,因为您将int值视为int ref值

在函数式编程中,您通常试图避免可变变量(ref值)

要详细说明您遇到的问题,请执行以下操作:

  • List.hd(List.nth(l,i)):=1
    意味着“将
    List.hd(List.nth(l,i))
    返回的引用设置为
    1
    。既然
    l
    是一个int列表,那么
    List.nth(l,i)
    返回该(或崩溃)元素的
    i
    th元素,这是一个int列表。然后
    List.hd(…)
    取其中的第一个元素(或崩溃),它是int,而不是int ref

    要使这一行正常工作,您需要
    l:int-ref-list-list

    但你不想这样

  • i=i-1
    是一个布尔表达式,如果
    i
    等于其自身减去1,则返回
    true
    。这对于任何整数都不是真的。您可能打算从
    i
    中减去1,并将结果放入
    i
    ,但您不能,因为
    i
    不是可变变量,并且是upd的运算符将ref命名为
    :=


如果您的问题是转换列表

val m = [ [ 1, 2, 3 ],
          [ 4, 5, 6 ],
          [ 7, 8, 9 ] ]
列入名单

val n = [ [ 1, 2, 3 ],
          [ 1, 5, 6 ],
          [ 1, 8, 9 ] ]
那么一个简单的方法就是使用
List.map

val n = List.map (fn row => 1 :: List.drop (row, 1)) m
一种更为手动的方法可以在迭代过程中实践递归和模式匹配,如
while…do
(只有在变量可变的情况下才有效)和部分函数,如
List.hd
List.nth
(可能崩溃),可以是:

fun f [] = []
  | f (row::m) = (1 :: List.drop (row, 1)) :: f m

val n = f m

如果你想要一个可变的版本,考虑模块而不是int列表。 下面是一个

Array2
解决方案,其中使用递归增加光标:

fun appulate f from to =
    if from > to then ()
    else (f from; appulate f (from+1) to)

fun f col m =
    appulate (fn row => Array2.update (m, row, col, 1))
             0 (Array2.nRows m - 1)

fun show m =
    Array2.appi Array2.RowMajor (fn (_, col, c) =>
      print (Int.toString c ^ (if col + 1 = Array2.nCols arr then "\n" else "" )))
      {base=arr,row=0,col=0,nrows=NONE,ncols=NONE};


val m' = Array2.fromList m
val n' = f 0 m'
val _  = show n'
我意识到,我没有给出任何
while…do
,或任何使用
ref
操作的int-ref集合的示例:=