Указатель NULL
- это тот, который указывает на никуда. Когда вы разыскиваете указатель p
, вы говорите «дайте мне данные в месте, хранящемся в« p ». Когда p
является нулевым указателем, местоположение, хранящееся в p
, является nowhere
, вы говорите «Дайте мне данные в месте« нигде ». Очевидно, он не может этого сделать, поэтому он выбрасывает NULL pointer exception
.
В общем, это потому, что что-то не было правильно инициализировано.
Быстрое Решение
просто необходимо добавить круглые скобки, или begin
/ end
, вокруг внутреннего соответствия:
let rec filter exp = match exp with | Var v -> Var v | Sum (e1, e2) -> Sum (e1, e2) | Prod (e1, e2) -> Prod (e1, e2) | Diff (e1, e2) -> (match e2 with | Sum (e3, e4) -> filter (diffRule e2) | Diff (e3, e4) -> filter (diffRule e2) | _ -> filter e2) | Quot (e1, e2) -> (match e2 with | Quot (e3, e4) -> filter (quotRule e2) | Prod (e3, e4) -> filter (quotRule e2) | _ -> filter e2) ;;
Упрощения
В Вашем особом случае нет никакой потребности во вложенном соответствии. Можно просто использовать большие шаблоны. Можно также устранить дублирование во вложенных правилах с помощью" |
" ("или") шаблоны:
let rec filter exp =
match exp with
| Var v -> Var v
| Sum (e1, e2) -> Sum (e1, e2)
| Prod (e1, e2) -> Prod (e1, e2)
| Diff (e1, (Sum (e3, e4) | Diff (e3, e4) as e2)) -> filter (diffRule e2)
| Diff (e1, e2) -> filter e2
| Quot (e1, (Quot (e3, e4) | Prod (e3, e4) as e2)) -> filter (quotRule e2)
| Quot (e1, e2) -> filter e2
;;
можно сделать его еще более читаемым путем замены неиспользованных переменных шаблона _
(подчеркивание). Это также работает на целые sub шаблоны такой как (e3,e4)
кортеж:
let rec filter exp =
match exp with
| Var v -> Var v
| Sum (e1, e2) -> Sum (e1, e2)
| Prod (e1, e2) -> Prod (e1, e2)
| Diff (_, (Sum _ | Diff _ as e2)) -> filter (diffRule e2)
| Diff (_, e2) -> filter e2
| Quot (_, (Quot _ | Prod _ as e2)) -> filter (quotRule e2)
| Quot (_, e2) -> filter e2
;;
Таким же образом, можно продолжить двигаться, упростив. Например, первые три случая (Var
, Sum
, Prod
) возвращаются неизмененные, который можно выразить непосредственно:
let rec filter exp =
match exp with
| Var _ | Sum _ | Prod _ as e -> e
| Diff (_, (Sum _ | Diff _ as e2)) -> filter (diffRule e2)
| Diff (_, e2) -> filter e2
| Quot (_, (Quot _ | Prod _ as e2)) -> filter (quotRule e2)
| Quot (_, e2) -> filter e2
;;
Наконец, можно заменить e2
[1 114] и замена match
с function
ярлык:
let rec filter = function
| Var _ | Sum _ | Prod _ as e -> e
| Diff (_, (Sum _ | Diff _ as e)) -> filter (diffRule e)
| Diff (_, e) -> filter e
| Quot (_, (Quot _ | Prod _ as e)) -> filter (quotRule e)
| Quot (_, e) -> filter e
;;
синтаксис шаблона OCAML хорош, не так ли?
Можно сделать это более кратким (и я спорил бы более ясный) разумным использованием подчеркиваний, as's и или-шаблоны. Получающийся код также более эффективен, потому что он выделяет меньше (в Var, Сумме и случаях Напоминания)
let rec filter = function
| Var _ | Sum _ | Prod _ as e -> e
| Diff (_, (Sum _ | Diff _) as e) -> filter (diffRule e)
| Diff (_,e) -> e
| Quot (_, (Quot _| Prod _) as e) -> filter (quoteRule e)
| Quot (_,e) -> filter e
;;