Да, сопоставление с образцом Меркурия работает иначе, чем в SML.Меркурий довольно строг в своей декларативной семантике.Предикат с несколькими предложениями эквивалентен дизъюнкции всех тел (по модулю некоторые сложности для объединений в главах клаузулы), и значение дизъюнкции не зависит от порядка, в котором пишутся различные ветви дизъюнкции.На самом деле очень мало Меркурия влияет на его значение в том порядке, в котором вы пишете вещи (переменные состояния - единственный пример, который я могу придумать).
Так что, не помещая N \= 0
в тело, ваш предикат с двумя предложениямииспользование сопоставления с шаблоном является недетерминированным.Ничто не могло бы помешать nth(Tl, 0 - 1, X)
быть действительным сокращением nth([_ | Tl], 0, X)
.
С N \= 0
вы идете по правильному пути.К сожалению, в то время как if A then B else C
логически эквивалентен (A, B) ; (not A, C)
, вывод детерминизма Меркурия обычно не достаточно умен, чтобы понять обратное.
В частности, вывод детерминизма Меркурия не делаетпопытаться выяснить в целом, что два пункта являются взаимоисключающими.В этом случае ему известно, что N = 0
может быть успешным или неудачным в зависимости от значения N
, и что N \= 0
может быть успешным или неудачным в зависимости от значения N
.Так как он видит два разных пути успеха предиката и может потерпеть неудачу, он должен быть недетерминированным.Есть способы пообещать компилятору, что детминизм не тот, который он вывел бы, но в подобных случаях проще просто использовать if / then / else.
Случаи, когда вы можете использовать сопоставление с образцом без компилятора, думая, что у вас может быть несколько решений, когда вы сопоставляете одну переменную с несколькими разными конструкторами одного типа.Например:
:- pred some_pred(list[T]) is det.
some_pred([]) :- something.
some_pred([H | T]) :- something_else.
Это называется switch .Компилятор знает, что список имеет два конструктора (пустой список []
или ячейка cons [|]
), и данный список может быть только одним из них, поэтому дизъюнкция (или несколько предложений предиката), которая имеетрука для обоих конструкторов должна быть детерминированной.Разъединение (несколько предложений) с падежами для некоторых, но не для всех конструкторов будет считаться полудетерминированным.
Меркурий также способен генерировать очень эффективный код для коммутаторов, а также уведомлять вас обо всех местахэто нужно изменить, когда вы меняете тип, добавляя новые случаи, поэтому считается хорошим стилем использовать переключатели там, где это возможно.Однако в таких случаях, как ваш, вы застряли с if / then / else.