在Mercury中,我可以将lambda声明为与包含lambda的谓词模式具有相同的确定性吗?
这就是我想要做的。我写了一个折叠函数(下面),它适用于array2d类型。 fold
为数组中的每个元素调用一个调用者提供的谓词。它工作正常,只要它只接受一个det谓词作为参数。
:- pred fold(array2d(T), pred(T, int, int, A, A), A, A).
:- mode fold(in, pred(in, in, in, in, out) is det, in, out) is det.
% Uncommenting the next line causes mode errors during compilation
% :- mode fold(in, pred(in, in, in, in, out) is semidet, in, out) is semidet.
fold(Array, Pred, !Accumulator) :-
bounds(Array, NumRows, NumCols),
FoldRows = (pred(RowNumber :: in, RowAccIn :: in, RowAccOut :: out) is det :-
FoldCols = (pred(ColNumber :: in, ColAccIn :: in, ColAccOut :: out) is det :-
Value = Array^elem(RowNumber, ColNumber),
Pred(Value, RowNumber, ColNumber, ColAccIn, ColAccOut)
),
int.fold_up(FoldCols, 0, NumCols - 1, RowAccIn, RowAccOut)
),
int.fold_up(FoldRows, 0, NumRows - 1, !Accumulator).
但我希望fold
接受det或semidet谓词(如果对谓词的任何调用失败,则会失败)。取消注释mode ... is semidet
行会给我编译错误,我不知道如何解决。问题是fold
中的lambdas被声明为det,所以他们不能调用semidet Pred
。如果我将lambda改为semidet,那么整个fold
就不能解除。
我该如何解决这个问题?似乎最直接的方法是声明lambdas从fold
谓词继承它们的确定性 - 所以当fold
被用作det时它们是det,同样对于semidet - 但是我不知道这是否可能。
当然,另一种方法是将FoldRows
和FoldCols
转换为具有多种模式的命名谓词(而不是lambdas)。但这很快变得不那么优雅了,我想知道是否有更直接的解决方案。
答案 0 :(得分:1)
Mercury有时可以推断谓词的模式和确定性,所以我最初通过省略lambda表达式中的determinism声明来尝试这一点。但是,Mercury的lambda语法不允许我这样做,所以这个推论不能用于lambdas。
我担心,正如您所猜测的那样,唯一的解决方案是将FoldRows和FoldCols转换为多模式命名谓词。