LiKao уже объяснил все ключевые моменты, но я подумал, что может иметь больше смысла, если вы вводите свои определения по одной строке за раз, которая показывает, какие ответы приходят от каких входных данных. Строки, введенные человеком, начинаются с #
.
# let p5 () = print_int 5;;
val p5 : unit -> unit = <fun>
Это определяет p5 как функцию, которая принимает значения типа unit
и возвращает значения типа unit
. Существует только одно значение типа unit, которое записывается как ()
. Так что это именно те скобки, о которых вы спрашиваете (я думаю). Обратите внимание, что ()
в вашем определении является шаблоном для значений, принимаемых функцией. Как шаблон, ()
соответствует самому себе (как и все константы, используемые в качестве шаблонов).
# p5 ();;
5- : unit = ()
Это немного сбивает с толку. 5
записывается вашей функцией p5
. Остальное - ответ от верхнего уровня OCaml. Это говорит о том, что результат вашего выражения имеет тип unit
и имеет значение ()
. Это имеет смысл, print_int
имеет тип int -> unit
.
# print_string "*************************";;
*************************- : unit = ()
Здесь похожая путаница. Звездочки *
написаны print_string
. Остальное показывает результат, который снова имеет тип unit
со значением ()
.
# let p4 = print_int 4;;
4val p4 : unit = ()
То же самое и здесь. 4
написано print_int
. Остальное показывает, что верхний уровень определил символ с именем p4
, тип которого unit
и значение ()
. Опять же, это имеет смысл, потому что print_int
возвращает тип unit
, а ()
- единственное значение этого типа. По типу p4
можно сказать, что это , а не функция. Функции имеют стрелку (->
) в типе. p4
это просто значение типа unit
.
# p4;;
- : unit = ()
Здесь вы запрашиваете у верхнего уровня тип и значение p4
, и он сообщает вам (снова), что p4
имеет тип unit
и имеет значение ()
.