1

在 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 也是如此——但我不知道这是否可能。

当然,另一种方法是转换为具有多种模式FoldRowsFoldCols命名谓词(不是 lambda)。但这很快就变得不优雅,我想知道是否有更直接的解决方案。

4

1 回答 1

1

Mercury 有时可以推断谓词的模式和确定性,所以我最初通过省略 lambda 表达式中的确定性声明来尝试这个。然而 Mercury 的 lambda 语法不允许我这样做,所以这个推断不能与 lambda 一起使用。

正如您所猜测的,恐怕唯一的解决方案是将 FoldRows 和 FoldCols 转换为多模式命名谓词。

于 2014-11-04T03:04:36.140 回答