Почему этот код работает в интерактивном режиме, но не работает при компиляции? - PullRequest
2 голосов
/ 03 февраля 2012

Я полный новичок в OCaml и пытаюсь создать простую консольную программу.

(*let k = read_int()
let l = read_int()
let m = read_int()
let n = read_int()
let d = read_int()*)

let k = 5
let l = 2
let m = 3
let n = 4
let d = 42

let rec total: int -> int -> int = fun i acc ->
  if i > d then
    acc
  else
    if (i mod k) == 0 || (i mod l) == 0 || (i mod m) == 0 || (i mod n) == 0 then
      total (i + 1) (acc + 1)
    else
      total (i + 1) acc;

print_int (total 1 0)

Но если я попытаюсь скомпилировать его, произойдет сбой:

PS C:\Users\user> ocamlc -g .\a148.ml
File ".\a148.ml", line 14, characters 2-180:
Warning S: this expression should have type unit.
File ".\a148.ml", line 22, characters 0-21:
Error: This expression has type unit but is here used with type int

Итак, похоже, if выражение не может вернуть значение здесь (почему?). Я добавил let привязка

let k = 5
let l = 2
let m = 3
let n = 4
let d = 42

let rec total: int -> int -> int = fun i acc ->
  let x' = if i > d then
      acc
    else
      if (i mod k) == 0 || (i mod l) == 0 || (i mod m) == 0 || (i mod n) == 0 then
    total (i + 1) (acc + 1)
      else
    total (i + 1) acc;
    x'
print_int (total 1 0)

и это работает, но вызывает другую ошибку:

File ".\a148.ml", line 23, characters 0-0:
Error: Syntax error

Строка 23 является следующей за print_int инструкцией и пустой, поэтому кажется, что компилятор хочет от меня чего-то другого, но я не знаю, что.

UPD: ок, рабочий код:

let k = 5 in
let l = 2 in
let m = 3 in
let n = 4 in
let d = 42 in
let rec total i acc =
  if i > d then
    acc
  else
    if (i mod k) == 0 || (i mod l) == 0 || (i mod m) == 0 || (i mod n) == 0 then
      total (i + 1) (acc + 1)
    else
      total (i + 1) acc
in let x = total 1 0 in
print_int x;

1 Ответ

2 голосов
/ 03 февраля 2012

Проблема заключается в неправильном использовании точки с запятой (;).

Точка с запятой намеревается быть последовательностью двух выражений.S1 ; S2 означает, что компилятор ожидает, что S1 будет иметь тип unit, вычисляет S1 и S2 в указанном порядке и возвращает результат S2.

Здесь вы по ошибке используете ;, поэтому OCaml ожидает, что второй if...then...else вернет unit, и хочет, чтобы вы предоставили еще одно выражение.Удаление ; и добавление необходимых in (s) должно привести к компиляции функции:

let k = 5 in
let l = 2 in
let m = 3 in
let n = 4 in
let d = 42 in

let rec total: int -> int -> int = fun i acc ->
  if i > d then
    acc
  else
    if (i mod k) == 0 || (i mod l) == 0 || (i mod m) == 0 || (i mod n) == 0 then
      total (i + 1) (acc + 1)
    else
      total (i + 1) acc

Что касается вашей второй функции, вы должны заменить ; на in, чтобы указать, что x'используется для вычисления возвращаемого значения.

Кстати, ваша функция total выглядит странно, поскольку вы используете лямбда-выражение в теле функции.Явное объявление более читабельно:

let rec total i acc = 
   if i > d then
      acc
   else if i mod k = 0 || i mod l = 0 || i mod m = 0 || i mod n = 0 then
      total (i + 1) (acc + 1)
   else
      total (i + 1) acc

Я также изменил ссылочное равенство (==) на структурное равенство (=), хотя между ними нет разницы в целых числах.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...