SMLNJ:运算符和操作数不一致 [tycon 不匹配] - 用于列表分配

SMLNJ: Operator & operand don't agree [tycon mismtach] - for list assignment

我在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 类型。但是,我不清楚 List.hdList.nth(l, i)) 将如何导致除 int.

以外的任何结果

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

SML/NJ 的错误消息并没有使这一点非常清楚。如果您将此代码放入 Moscow ML 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) returns 那个(或崩溃)的第 i 个元素,它是一个 int 列表 。然后 List.hd(...) 取第一个元素(或崩溃),它是 int。不是 int ref

    要使此行正常工作,您需要 l : int ref list list.

    但你不想这样。

  • i = i - 1是一个布尔表达式,即returns true if i 等价于自身减1。这对任何整数。您可能打算从 i 中减去 1 并将结果放入 i,但您不能这样做,因为 i 不是可变变量,并且更新 [=74] 的运算符=]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.hdList.nth (可能会崩溃)可能是:

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

val n = f m

如果你想要一个可变版本,请考虑 Array2 模块而不是 int list list.

这是一个 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 的任何示例,也没有给出 int ref 的任何集合ref , !:=.