В Ocaml первый символ идентификатора используется для определения его синтаксического класса. В частности,
- переменные
- типы
- поля записи
- классы
- типы классов
- экземпляр переменные
должны начинаться со строчной буквы. Напротив,
должны начинаться с заглавной буквы. (Это 5 исключений для конструкторов []
, ()
, (::)
, true
и false
). И
- типы модулей
- polymorphi c варианты конструкторов
могут начинаться со строчной или прописной буквы. Однако более логично c использовать для них заглавные буквы.
Так что если вы определяете
let rec H n =
if n == 0 then
0
else
n - H(H(H(n - 1)))
, то компилятор читает H
как конструктор, и поэтому он думает, что что вы пытаетесь определить переменную аналогично
type t = C of int
let (C n) = C 1
Другими словами, решение вашей проблемы - переименовать вашу переменную h
:
let rec h n =
if n = 0 then
0
else
n - h(h(h(n - 1)))
( Не используйте ==
для не изменяемой переменной в OCaml.
Если вам интересно, почему существует такое различие между Конструкторами и переменными, одна из основных причин заключается в том, что в противном случае становится возможным написать какое-то очень запутанное сопоставление с образцом. Рассмотрим, например,
type t =
| X
| Y
| Z
let f x = match x with
| X -> 0
| y -> 1
в первой ветви сопоставления с шаблоном
| X -> 0
, мы проверяем, является ли x
конструктором X
. Однако во второй ветви,
| y -> 1
мы переименовываем переменную x
в y
в ветви. Здесь мы можем использовать регистр первого символа, чтобы узнать, в каких случаях мы находимся. Без этого синтаксического различия нам нужно будет помнить, был ли конструктор X
или y
в области видимости во время сопоставления с образцом.