简体   繁体   English

如何像在 Prolog 中一样在 Mercury 中生成新变量列表?

[英]How to generate lists of fresh variables in Mercury like I can in Prolog?

In SWI Prolog, list(Xs):- length(Xs, _).在 SWI Prolog 中, list(Xs):- length(Xs, _). is "pure" in that I can pass it a variable with any sort of instantiatedness and it will nondeterministically unify it with all most general unifiers of a particular length.是“纯粹的”,因为我可以将具有任何类型实例化的变量传递给它,并且它将不确定地将它与特定长度的所有最通用的统一符统一起来。

Is it possible to write a pure list/1 in Mercury?是否可以在 Mercury 中编写纯list/1 The manual seemed to hint this could be done , but I'm having trouble actually implementing it. 该手册似乎暗示可以做到这一点,但我在实际实施时遇到了麻烦。

What I have so far is:到目前为止,我所拥有的是:

:- module mylist.

:- interface.

:- import_module list.

:- inst frees for list/1
    --->    []
    ;       [free | frees].
:- mode free_to_frees == free >> frees.

:- pred mylist(list(_)).
:- mode mylist(in) is det.
:- mode mylist(free_to_frees) is multi.

:- implementation.

:- pragma promise_pure(mylist/1).

mylist(_::in).

mylist([]::free_to_frees).
mylist([_|Xs]::free_to_frees) :- mylist(Xs).

However, when I try this:但是,当我尝试这个时:

:- module main.
:- interface.
:- implementation.
:- import_module list, mylist.

:- pred getlist(list(int)).
:- mode getlist(free >> ground) is multi.
getlist(Xs) :- Xs = [1, 2, 3].
getlist(Xs) :- mylist(Xs), Xs = [5].

I get the following error:我收到以下错误:

main.m:011: In clause for `getlist(out)':
main.m:011:   mode error in conjunction. The next 2 error messages indicate
main.m:011:   possible causes of this error.
main.m:011:   
main.m:011:   In clause for `getlist(out)':
main.m:011:   mode error in unification of `Xs' and `list.[V_10 | V_16]'.
main.m:011:   Variable `Xs' has instantiatedness
main.m:011:     bound(
main.m:011:       []
main.m:011:     ;
main.m:011:       '[|]'(
main.m:011:         free,
main.m:011:         named inst mylist.listskel,
main.m:011:         which expands to
main.m:011:           bound(
main.m:011:             []
main.m:011:           ;
main.m:011:             '[|]'(
main.m:011:               free,
main.m:011:               named inst mylist.listskel
main.m:011:             )
main.m:011:           )
main.m:011:       )
main.m:011:     ),
main.m:011:   term `list.[V_10 | V_16]' has instantiatedness
main.m:011:   `named inst list.'[|]'(unique(5), free)'.
main.m:011:   
main.m:011:   In clause for `getlist(out)':
main.m:011:   in argument 1 of clause head:
main.m:011:   mode error in unification of `HeadVar__1' and `Xs'.
main.m:011:   Variable `HeadVar__1' has instantiatedness `free',
main.m:011:   variable `Xs' has instantiatedness
main.m:011:     bound(
main.m:011:       []
main.m:011:     ;
main.m:011:       '[|]'(
main.m:011:         free,
main.m:011:         named inst mylist.listskel,
main.m:011:         which expands to
main.m:011:           bound(
main.m:011:             []
main.m:011:           ;
main.m:011:             '[|]'(
main.m:011:               free,
main.m:011:               named inst mylist.listskel
main.m:011:             )
main.m:011:           )
main.m:011:       )
main.m:011:     ).

I'm guessing my use of free may be incorrect, or else I need to add an additional mode or generalize my listskel inst to cover the case of mylist(Xs), Xs = [5] .我猜我对free的使用可能不正确,否则我需要添加一个额外的模式或概括我的listskel inst 以涵盖mylist(Xs), Xs = [5]的情况。

Basically, how should I write mylist/1 , so that it can be used in as many modes as possible?基本上,我应该如何编写mylist/1 ,以便可以在尽可能多的模式下使用它?

Thank you!谢谢!

Due to a limitation in the Mercury implementation, which is documented in the LIMITATIONS file in the Mercury distribution, what you ask for cannot be done.由于 Mercury 实现的限制(记录在 Mercury 发行版的 LIMITATIONS 文件中),您要求的内容无法完成。

While the design of the Mercury language allows modes that describe partially instantiated terms such as a list of free variables, such as the intended output of mylist(Xs) , such terms are not useful unless you can do something with them, such as unify them with [5] .虽然 Mercury 语言的设计允许描述部分实例化术语的模式,例如自由变量列表,例如mylist(Xs)的预期 output,但这些术语没有用,除非您可以对它们做一些事情,例如统一它们与[5] Since the Mercury compiler needs to know the instantiation state of all variables at all program points, it can allow this only if it can keep track of all unifications between free variables in such terms with other free variables (whether they occur in such terms or not).由于 Mercury 编译器需要知道所有程序点处所有变量的实例化 state,因此只有当它可以跟踪此类术语中的自由变量与其他自由变量之间的所有统一时(无论它们是否以此类术语出现),它才能允许这样做)。 This is because if you have unifications A = B , B = C , and C = D , and then you unify D with 5 , the compiler needs to know that this grounds not just D , but A , B and C as well. This is because if you have unifications A = B , B = C , and C = D , and then you unify D with 5 , the compiler needs to know that this grounds not just D , but A , B and C as well. This is because those unifications have made A , B and C aliases of D (ie they are other ways to refer to D ).这是因为这些统一使ABC成为D别名(即它们是引用D的其他方式)。

When Mercury was first implemented in the mid-1990s, we had a student working on alias tracking.当 Mercury 在 1990 年代中期首次实施时,我们有一名学生从事别名跟踪工作。 Unfortunately, what he found was that while alias tracking is possible , it was not feasible , in that it switching on alias tracking usually at least doubled the time required to compile a module.不幸的是,他发现虽然别名跟踪是可能的,但这并不可行,因为它打开别名跟踪通常至少会使编译模块所需的时间增加一倍 We considered this to be too high a price to pay for a capability that was just about never used.我们认为这对于几乎从未使用过的功能付出的代价太高了。 And even though today, due to Moore's law, the absolute cost of alias tracking would be much smaller, the relative tradeoffs haven't really changed, and we now have a couple of decades experience in working with Mercury in which we have found so few situations in which support for filling in partially instantiated data structures would be useful that off the top of my head I can't remember any of them.即使在今天,由于摩尔定律,别名跟踪的绝对成本会小得多,相对的权衡并没有真正改变,而且我们现在有几十年的使用 Mercury 的经验,我们在其中发现的很少在某些情况下,支持填充部分实例化的数据结构会很有用,但我一时想不起来它们中的任何一个。

Programming in Mercury is quite different from programming in Prolog. Mercury 中的编程与 Prolog 中的编程完全不同。 This is by design.这是设计使然。 In Mercury, instead of building a partially instantiated term and then filling it in, you would simply construct the final term directly.在 Mercury 中,您无需构建部分实例化的术语然后填充它,而是直接构建最终术语。 For any programmer interested in program reliability, this would be the preferred course of action even when working in Prolog.对于任何对程序可靠性感兴趣的程序员,即使在 Prolog 中工作,这也是首选的做法。 In real Prolog programs, as opposed to puzzle solvers or student exercises, leaving part of a term uninstantiated is far more likely to be an error than not.在实际的 Prolog 程序中,与解谜程序或学生练习相反,将部分术语未实例化的可能性要大得多。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM