在 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
行会给我带来我不知道如何解决的编译器错误。问题是 lambdafold
被声明为 det,所以它们不能调用 semidet Pred
。如果我将 lambdas 更改为 semidet,那么fold
作为一个整体就无法确定。
我该如何解决这个问题?似乎最直接的方法是声明 lambdas 从fold
谓词继承它们的确定性——所以当它们fold
被用作 det 时,它们是 det,对于 semidet 也是如此——但我不知道这是否可能。
当然,另一种方法是转换为具有多种模式FoldRows
的FoldCols
命名谓词(不是 lambda)。但这很快就变得不优雅,我想知道是否有更直接的解决方案。