SMLNJ: оператор и операнд не согласны [tycon mismtach] - для назначения списка - PullRequest
0 голосов
/ 02 июня 2018

Я написал следующую функцию в 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.

. Пожалуйста, сообщите, как я могу исправить эту ошибку и поддерживающую логику.

1 Ответ

0 голосов
/ 02 июня 2018

Сообщение об ошибке SML / NJ не делает это ужасно ясным.Если вы поместите этот код в REPL Moscow ML и включите функцию 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 -й элемент этого (или аварийного завершения), который является int списком Затем List.hd(...) принимает 1-й элемент этого (или аварийно завершает работу), который является int . Не int ref .

    Чтобы эта строка работала,вам понадобится l : int ref list list.

    Но вы этого не хотите.

  • i = i - 1 - это логическое выражение, которое возвращает true, если i эквивалентно мнеСебе минус 1. Это не так для любого int .Вы, вероятно, намереваетесь вычесть 1 из i и поместить результат в i, но вы не можете, потому что i не является изменяемой переменной, и вызывается оператор для обновления ref :=.


Если ваша проблема заключалась в преобразовании списка

val m = [ [ 1, 2, 3 ],
          [ 4, 5, 6 ],
          [ 7, 8, 9 ] ]

в список

val n = [ [ 1, 2, 3 ],
          [ 1, 5, 6 ],
          [ 1, 8, 9 ] ]

, тогда aкороткий способ сделать это - использовать 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

Если вам нужна изменяемая версия, рассмотрите модуль Array2 вместо списка int 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 s, которыеh работает с ref, ! и :=.

...