如何读取文件并创建列表的列表?Prolog代码改造求助
解决Prolog中收集16个列表到嵌套列表的问题
嘿,我明白你现在的需求——原来的代码每次读取一行转换后直接打印,但你想把这16次的FinalLine收集成一个大的嵌套列表,对吧?
首先得说,你原来用的repeat-fail循环虽然能重复执行,但这种回溯式的结构不太适合保留中间结果,因为每次失败回溯都会重置变量。Prolog里处理这种“收集多个结果”的需求,最常用也最符合纯逻辑风格的方法是累加器(Accumulator),也就是用递归逐步把结果攒起来。
下面是修改后的完整代码,我会一步步解释:
main :- open('input.txt', read, Input), read_16_lines(Input, [], AllLines), % 初始累加器是空列表 close(Input), % 这里可以替换成你对AllLines的后续操作,比如打印、处理等 writeln(AllLines). % 递归终止条件:已经收集够16行,反转累加器得到正确顺序 read_16_lines(_Input, Acc, Result) :- length(Acc, 16), !, % 切断回溯,避免多余匹配 reverse(Acc, Result). % 递归步骤:读取一行、转换、加入累加器 read_16_lines(Input, Acc, Result) :- read_line_to_codes(Input, Line), Line \= end_of_file, % 额外做个安全判断,防止文件提前结束 maplist(my_representation, Line, FinalLine), read_16_lines(Input, [FinalLine|Acc], Result).
关键逻辑说明:
- 累加器的使用:我们用
read_16_lines/3这个自定义谓词来处理核心的收集逻辑。初始时累加器Acc是空列表,每次递归都会把新生成的FinalLine加到累加器的头部(这样做是为了尾递归优化,效率更高)。 - 终止条件:当累加器的长度达到16时,我们停止递归,并且把累加器反转——因为每次加在头部,最后得到的顺序是逆的,反转后就和输入文件的行顺序一致了。
!是切断回溯的操作,防止Prolog继续尝试其他分支。 - 替代原有的writeln:原来的
writeln(FinalLine)被替换成了把FinalLine加入累加器的操作,这样所有结果都会被保留在AllLines里,供后续使用。
如果你坚持想用类似原代码的repeat-fail结构(虽然不推荐,因为已知固定次数,递归更清晰),也可以用动态断言的方式(比如assertz(line(FinalLine))),但这种方式会引入副作用,破坏Prolog的纯逻辑特性,所以还是累加器的方法更优。
另外,假设你的my_representation/2已经正确实现了把输入字符转换为包含下划线和整数的列表的逻辑,这个代码就能直接工作啦。
内容的提问来源于stack exchange,提问作者Jacob
相关产品推荐
相关产品推荐

