假设我有一个长度为 9 的唯一列表,其中包含 1 和 9 之间的值(包括随机顺序)(想想数独),我想提取出现在值 1 和 9(不包括)之间的项目的子列表. IE:between1and9([1,3,5,4,2,9,7,8,6],[3,5,4,2])
应该是真的。
目前我正在尝试使用flatten/2
,但运气不佳。这是我目前的策略(假设我List ins 1..9, maplist(all_distinct, List), length(List, 9)
在其他地方强制执行以保持此处整洁/关注点分离):
between1and9(List,Between) :-
flatten([_,[1],Between,[9],_], List);
flatten([_,[9],Between,[1],_], List).
List
当 1 或 9 在 中的第一个或最后一个位置,或者它们在 中相邻时,此版本会失败List
。between1and9([_,1,9,_,_,_,_,_,_],[])
是真的,但是between1and9([_,1,9,_,_,_,_,_,_],_)
是假的(当我试图用它作为约束来解决更大的问题时失败了。)
两次失败似乎都是同一个问题,flatten
似乎不喜欢将未知数视为空列表,除非它们在某处明确。
我可以理解为什么会这样,如果flatten
可以在第一个参数中“发明”空列表,这将意味着第一个参数中任何内容的无限解决方案。尽管我的完整程序有其他限制来防止这种情况,但我可以理解为什么flatten
可能不想适应它。
我可以通过将每个排列与析取匹配来解释边缘情况(双关语)(即:flatten([_,1,B,9,_],L);flatten([_,9,B,1,_],L);flatten([_,1,B,9]);flatten...
,并将 Between 解释为一个空列表:\*above permutations on flatten*\; ( Between = [], (\*permutations for either edge and 1/9*\) )
但这似乎使一个已经冗长的解决方案(总共 10 个 flatten 排列)更糟(18 个)所以我有两个(密切相关的)问题:
如果我能做到以下几点:
between1and9(L,B) :- ( ( X = 1, Y = 9 ); ( X = 9, Y = 1 ) ), ( ( Z1 = _; Z1 = [] ), ( Z2 = _ ; Z2 = [] ) ), ( B = _; B = [] ), flatten([Z1,X,B,Y,Z2],L).
我不必手动输入 match for 的每个排列
flatten
。不幸的是,这和它的一些变化都单方面失败了。我在这里遗漏了一些明显的东西吗?(我怀疑运算符优先级,但我尝试了几个不同的版本。)还是我这样做完全错了?文档表明,在大多数情况下,
flatten/2
它是一种反模式,是否有更 prolog-ish* 的方式来解决这个问题?考虑到我在经历这个过程中意识到的所有陷阱,我几乎可以肯定存在。
(对不起,我很痛苦地意识到我用来描述事情的很多术语可能是非常错误的,我只熟悉谓词/形式逻辑,更习惯于描述控制流类型编程。尽管我在实践中对逻辑编程的理解相当好,但我仍在努力寻找一种语言来有力地谈论它,但我会用我得到的任何更正来修改这个问题。)
一些背景:我是序言的新手,通过尝试扩展众多数独求解器中的一个来解决我在几年前打印出来的一些谜题中发现的各种奇怪的数独,来测试我的理解在任何给定行或列中出现在 1 和 9 之间的数字作为额外提示,有点像数独和 picross 的混合。现在的求解器正在运行:SumSudoku(swish)。虽然当你到达它时可能会一团糟。
*推论问题:是否有“pythonic”这个词的序言版本?