Yap和SWI-Prolog读取规范列表的区别

4
我有以下测试代码尝试将文件读入列表中。
open('raw250-split1.pl', read, Stream),
read(Stream,train_xs(TrainXs)),
length(TrainXs, MaxTrain).

我会省略部分输出,因为文件非常大。
它可以很好地与“yap”一起使用。
➜  chill git:(master) ✗ yap                                                      [18/06/19| 5:48PM]
% Restoring file /usr/lib/Yap/startup.yss
YAP 6.2.2 (x86_64-linux): Sat Sep 17 13:59:03 UTC 2016
   ?- open('raw250-split1.pl', read, Stream),                                                           
      read(Stream, train_xs(TrainXs)),                                                                     
      length(TrainXs, MaxTrain).
MaxTrain = 225,
Stream = '$stream'(3),
TrainXs = [[parse([which,rivers,run,through,states,bordering,new,mexico,/],answer(_A,(river(_A),traverse(_A,_B),next_to(_B,_C),const(_C,stateid('new mexico')))))],
<omited output>
,[parse([what,is,the,largest,state,capital,in,population,?],answer(_ST,largest(_SU,(capital(_ST),population(_ST,_SU)))))]]

但是在 swi-prolog 上,它会产生 类型错误(Type error)
➜  chill git:(master) ✗ swipl                                                     [18/06/19| 7:24PM]
Welcome to SWI-Prolog (threaded, 64 bits, version 7.6.4)
SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software.
Please run ?- license. for legal details.

For online help and background, visit http://www.swi-prolog.org
For built-in help, use ?- help(Topic). or ?- apropos(Word).

?- open('raw250-split1.pl', read, Stream),    
   read(Stream, train_xs(TrainXs)),                                                                     
   length(TrainXs, MaxTrain).
ERROR: raw250-split1.pl:4:
    Type error: `list' expected, found `parse(which.(rivers.(run.(through.(states.(bordering.(new.(mexico.((/).[])))))))),
    <omited output>
,answer(_67604,(state(_67604),next_to(_67604,_67628),const(_67628,stateid(kentucky))))).[].(parse(what.((is).(the.(largest.(state.(capital.(in.(population.((?).[])))))))),answer(_67714,largest(_67720,(capital(_67714),population(_67714,_67720))))).[].[]))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))' (a compound)
    In:
      [10] throw(error(type_error(list,...),context(...,_67800)))
       [7] <user>

    Note: some frames are missing due to last-call optimization.
    Re-run your program in debug mode (:- debug.) to get more detail.

这里出错的问题可能是什么?
如果你想尝试,可以从下面的ftp url中找到raw250-split1.pl文件。
谢谢帮助!
我正在尝试将早期代码迁移到SWI-Prolog,该代码是由Raymond J. Mooney在SICStus 3#3:Thu Sep 12 09:54:27 CDT 1996或更早版本编写的,其FTP地址为:ftp://ftp.cs.utexas.edu/pub/mooney/chill/。所有这个标签的问题都与此任务相关。我是Prolog的新手,欢迎提供帮助和建议!

考虑使用SICStus 4:它有一个非常快速的JIT编译器。 - false
@false 谢谢!我们学校没有许可证。我安装了一个进行评估。当它过期时,只需重新申请另一个即可。 - Vimos
3个回答

4

显然,raw250-split1.pl 是使用经典表示法编写的。传统的列表函数符号是 ./2,但 SWI-Prolog 7.x 将其改为 '[|]'/2,以便将 ./2 用于其他目的。这会导致变量 TrainXsread/2调用实例化为一个复合术语,其参数不是列表:

?- open('raw250-split1.pl', read, Stream), read(Stream,train_xs(TrainXs)).
Stream = <stream>(0x7f8975e08e90),
TrainXs = parse(which.(rivers.(run.(through.(states.(bordering.(... . ...)))))), answer(_94,  (river(_94), traverse(_94, _100), next_to(_100, _106), const(_106, stateid('new mexico'))))).[].(parse(what.((is).(the.(highest.(point.(... . ...))))), answer(_206,  (high_point(_204, _206), const(_204, stateid(montana))))).[].(parse(what.((is).(the.(most.(... . ...)))), answer(_298, largest(_300,  (population(_298, _300), state(...), ..., ...)))).[].(parse(through.(which.(states.(... . ...))), answer(_414,  (state(_414), const(..., ...), traverse(..., ...)))).[].(parse(what.((is).(... . ...)), answer(_500, longest(_500, river(...)))).[].(parse(how.(... . ...), answer(_566,  (..., ...))).[].(parse(... . ..., answer(..., ...)).[].(parse(..., ...).[].(... . ... .(... . ...))))))))).

YAP仍然使用./2作为列表的函数子,这就解释了为什么它可以处理它。对于SWI-Prolog的解决方法是使用--traditional命令行选项启动它:

$ swipl --traditional
...
?- open('raw250-split1.pl', read, Stream), read(Stream,train_xs(TrainXs)).
Stream = <stream>(0x7faeb2f77700),
TrainXs = [[parse([which, rivers, run, through, states, bordering|...], answer(_94,  (river(_94), traverse(_94, _100), next_to(_100, _106), const(_106, stateid('new mexico')))))], [parse([what, is, the, highest, point|...], answer(_206,  (high_point(_204, _206), const(_204, stateid(montana)))))], [parse([what, is, the, most|...], answer(_298, largest(_300,  (population(_298, _300), state(...), ..., ...))))], [parse([through, which, states|...], answer(_414,  (state(_414), const(..., ...), traverse(..., ...))))], [parse([what, is|...], answer(_500, longest(_500, river(...))))], [parse([how|...], answer(_566,  (..., ...)))], [parse([...|...], answer(..., ...))], [parse(..., ...)], [...]|...].

你得到的类型错误是由于第一个参数被绑定时,length/2期望一个列表。

SWI的当前版本可以轻松解析和突出显示该源代码。现在我也将尝试read/2。 - CapelliC
谢谢你们两个!学习prolog时,兼容性似乎是一个真正的挑战。 - Vimos
我可以确认read/2也能正常工作,问题确实是EOF处的波浪号。 - CapelliC
迁移到 yap 可以运行,但现在出现了错误,似乎还需要在 swi-prolog 上做更多的工作。感谢您的帮助! - Vimos
@CapelliC 在我的电脑上,添加 --traditional 也可以与那个波浪符号一起使用。 - Vimos
抱歉,我没有理解好问题,发了一些无关的内容。实际上,这与您所解释的相关。 - CapelliC

1
那个文件以波浪线结尾,导致语法无效,因此在阅读之前应将其删除。我不知道为什么YAP认为该文件有效,应该会出错。

我尝试去掉那个波浪符,但错误仍然存在。 - Vimos
是的,我忽略了那个,但它很可能不相关。你确定你从实际读取的文件中删除了波浪号吗? - CapelliC
我用 tail 再次确认了一下,))))))))). - Vimos

1

在SWI-Prolog中有一个read选项dotlists/2:

dotlists(Bool)
如果为true(默认为false),则将.(a, []) 读取为列表,即使使用点作为函数符号构造内部列表也不例外。这主要用于从其他Prolog系统中读取write_canonical/1的输出。请参见5.1节。 http://www.swi-prolog.org/pldoc/man?predicate=read_term/2

这样可以给出您想要的结果,而不改变模式:

Welcome to SWI-Prolog (threaded, 64 bits, version 8.1.0)

?- read_term(X, [dotlists(true)]).
|: .(a,.(b,.(c,[]))).
X = [a, b, c].

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接