Существуют англоязычные списки часто задаваемых вопросов и ответов на них:
Чьё-то введение в функциональное программирование на русском языке
Unix system programming in Objective Caml by Xavier Leroy and Didier Rémy
How to Think Like a Computer Scientist by Nicholas Monje and Allen Downey
Crash course on Caml and type systems by Xavier Leroy (скорее на французском, чем на английском)
Туториал
В чём различие между "=" и "=="?
"=" – структурное сравнение, "==" – физическое сравнение.
Структурное сравнение – сравнение на равенство структуры значений. Если значение является массивом, его структура – массив определённой длины, состоящий из значений, поэтому при сравнении двух массивов на структурное равенство проверяется равенство длин массивов и структурное равенство каждого из их элементов. То есть, сравнение идёт рекурсивно по структуре значений. Поэтому оно может не завершаться в случаях циклических структур данных.
Для изменяемых значений (массивов, ссылок, записей с изменяемыми полями) верно следующее: если изменение элемента/содержимого/поля a1
влечёт за собой изменение a2
, то a1 == a2
.
Подробнее – смотрите описание модуля Pervasives про функции "=" и "==".
Где точка входа в программу на окамле?
Одной конкретной точки входа нет. Программа состоит из модулей, линкуемых в определённом порядке. В этом же порядке, для каждого модуля, входящего в программу, вычисляются значения верхнего уровня модуля в порядке их определения (сверху вниз). Несмотря на это, рекомендуем сделать функцию наподобие main
, из которой уже вызывать основные функции программы, и вычислять значение этой функции в качестве последнего вычисляемого значения верхнего уровня последнего линкуемого модуля. Остальные значения верхнего уровня рекомендуем делать такими, чтобы они не вызывали сайд-эффектов. То есть, что-то наподобие:
ocaml
let func1 a = ...
let func2 b = ...
let main () = (func1 123; func2 234)
let () = main ()
В чём различие между let _ = ..
и let () = ..
?
let _ = ..
позволяет любое выражение справа – любое значение любого типа. let () = ..
соответствует только значению () : unit
. Если известно, что функция используется только для сайд-эффектов или, в общем случае, возвращает ()
, безопаснее будет использовать let () = func args
, чтобы случайно не пропустить частичное применение наподобие
ocaml
let _ = Printf.printf "two ints are: %i and %i" 123
В этом случае не будет выведено ничего (к _
будет привязана функция с типом int -> unit
). let () = ..
в этом случае сообщил бы, что тип этой функции не соответствует типу unit
.
Если же знаете, что функция возвращает значение известного типа (не unit
), которое нужно игнорировать, можно улучшить ошибкозащищённость и поддерживаемость программы, указав, значение какого типа хотим игнорировать, например:
ocaml
let skip_line ch =
let (_ : string) = input_line ch in ()
Это полезно как для того, чтобы избежать случайного частичного применения как во время написания кода, так и на будущее: если в функцию будут добавлены параметры, будет то же самое частичное применение, не отлавливаемое компилятором в случае let _ = ..
.
Как указать тип функции в реализации (.ml)?
let fn : ('a -> 'b -> 'c) = fun a b -> c
let fn (a:'a) (b:'b):'c = c
Много разных библиотек, модулей, функций, типов -- как найти
нужную мне сейчас функцию?
Штатный ocamlbrowser на вид не очень эстетичен, однако весьма
практичен, если научиться запускать его как
`ocamlfind ocamlbrowser -all` -- "запустить с полным списком
установленных пакетов", либо `ocamlfind ocamlbrowser -package pkg1,pkg2`
для списка выбранных пакетов.
Далее -- просмотр списка модулей, поиск по именам модулей и
значений, даже какой-то поиск по типам есть (но не работает
так, как велит интуиция, для запросов вида `'a -> 'b -> 'a` --
считает, что конкретные `'a` не связаны друг с другом).