Содержание
- Нулевые значения
Утверждения,
предупреждения, фатальные ошибки и вывод на stderr
Нулевые значения
Предположим, что на своём сайте вы
решили провести исследование, дабы узнать у читателей их возраст и
имена. Существует только проблема в том, что по некоторым
причинам, некоторые из ваших читатели не хотят указывать свой
возраст, упрямо отказываясь заполнять соответствующую область.
Что, в данном случае, должен делать бедный администратор базы
данных?
Предположим, что возраст
представлен как int , тогда у нас есть два возможных
способа решить сложившуюся проблему. Наиболее обычный (и наиболее
неправильный) способ заключается в принятии "некоторого"
значения когда возраст не будет обработан. Предположим, когда
возраст = -1, тогда информация не будет принята, в противном
случае она будет прината (даже если в корне неверна!). Этот способ
работает если вы, для примера, решили выяснить средний возраст
посетителей своего сайта. Забыв учесть некоторые значения вы
решаете, что средний возраст ваших посетителей 7½, наняв
web дизайнеров для удаления длинных слов и подбора текущей
цветовой схемы.
Другой, более корректный способ,
состоит в том, чтобы хранить возраст в области которая имеет тип
"int или null". Вот SQL таблица для хранения возрастов:
create table users
(
userid serial,
name text not null,
age int -- may be null
);
Если данные о возрасте не получены тогда в базу отправляется
специальное SQL значение null . SQL автоматически его
игнорирует когда вы запрашиваете вычислить среднее число или
что-нибудь в таком духе.
В языках программирования тоже
реализована поддержка нулевых значений, причём в одних эти
значения легче использовать, чем в других. Например в Perl любой
scalar (то есть число или строка) может быть обозначен как undef
(способ определения нулевого значения в Perl). Это вызывает
множество опасных моментов, которые часто игнорируются неопытными
программистами, что может привести к серьёзным ошибкам. В Java
любая ссылка на объект тоже может быть нулевой, потому в Java
имеет смысл хранить возраст как Integer и позволить
ссылкам на возраст быть null . В C значения тоже могут
быть нулевыми, но если вы бы хотели, чтобы простое целое число
было нулевым, вам необходимо в начале боксировать его в объект
размещённый в malloc .
OCaml предлагает элегантное
решение этой проблемы, используя простой вариант определения
полиморфного типа:
type 'a option = None | Some of 'a
В данном случае нулевое значение обозначено как None .
В примере выше, тип возраста (int которое может быть
нулевым) является int option [Помните: выводы навроде
int list и int binary_tree ].
# Some 3;;
- : int option = Some 3
А, что на счёт списка дополнительных целых чисел?
# [ None; Some 3; Some 6; None ];;
- : int option list = [None; Some 3; Some 6; None]
А, как на счёт дополнительного списка целых чисел?
# Some [1; 2; 3];;
- : int list option = Some [1; 2; 3]
Утверждения, предупреждения, фатальные ошибки и
вывод на stderr
Одна замечательная особенность
Perl'a — богатый набор команд для отладки программ и
обработки неожиданных ошибок, включая способность печатать стек
трассировки, отсылать и ловить исключения (более подробно об
исключениях мы поговорим позже), ну и так далее. OCaml имеет не на
столько богатый набор отладочных команд то, что есть просто лучше
чем Java, схоже с C и не столь хорошо как в Perl.
Прежде всего следует рассказать об
assert которая берёт выражение как аргумент и
отсылает исключение. Предположим, что вам не удалось поймать это
исключение (неразумно ловить исключения, особенно новичкам), в
таком случае результатом станет остановка программы, вывод
исходного файла и номера строки где произошла ошибка. Например:
# assert (Sys.os_type = "Win32");;
Exception: Assert_failure ("", 0, 30).
Разумеется запуск этого кода на Win32 не вызовет ошибку.
Если в вашей программе, что-то
пошло не так, вы можете использовать assert false для
её остановки, но лучше всего для этой целей подойдёт...
failwith "error
message" отправляет Failure исключение,
которое не будучи поймано, остановит программу и выдаст вам "error
message". failwith часто используется в процессе
сравнения с образцом, как в этом примере:
match Sys.os_type with
"Unix" | "Cygwin" -> (* code omitted *)
| "Win32" -> (* code omitted *)
| "MacOS" -> (* code omitted *)
| _ -> failwith "this system is not supported"
Обратите внимание на две особенности сравнения с образцом, в этом
примре. Так называемый "range pattern" используется для
проверки соответствия "Unix" или "Cygwin" ,
а специальный символ _ обозначает "что-нибудь ещё".
Если вы, как и я, хотите провести
отладку своей программы, но испытываете жуткую неприязнь к
отладчикам, окромя gdb, в таком случае вы возможно пожелаете
вывести ошибку через свою собственную функцию. Например (обратите
внимание на код помеченый красным):
open Graphics;;
open_graph " 640x480";;
for i = 12 downto 1 do
let radius = i * 20 in
prerr_endline ("radius is " ^ (string_of_int radius));
set_color (if (i mod 2) = 0 then red else yellow);
fill_circle 320 240 radius
done;;
read_line ();;
Если вы предпочитаете printf в C-стиле, тогда
используйте OCaml модуль Printf :
open Graphics;;
open Printf;;
open_graph " 640x480";;
for i = 12 downto 1 do
let radius = i * 20 in
printf "radius is %d\n" radius;x
set_color (if (i mod 2) = 0 then red else yellow);
fill_circle 320 240 radius
done;;
read_line ();;
|