我在 Haskell 中有一个列表理解,我想将其翻译为 Prolog。
列表理解的要点是旋转 4 x 4 网格:
rotate :: [Int] -> [Int]
rotate grid = [ grid !! (a + 4 * b) | a <- [0..3], b <- [0..3] ]
现在在 Prolog 中,我是这样翻译的:
rotateGrid([T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15],
[T0,T4,T8,T12,T1,T5,T9,T13,T2,T6,T10,T14,T3,T7,T11,T15]).
我们能做得更好吗?
最佳答案
我们可以使用findall/3
对于列表推导(参见 SWI-Prolog Documentation)。例如。,
?- findall(X, between(1,10,X), Xs).
Xs = [1,2,3,4,5,6,7,8,9,10]
Xs
是一个包含所有可以与 X
统一的值的列表当X
是一个介于 1 和 10 之间的数字。这大致相当于 Haskell 表达式 let Xs = [x | x <- [1..10]]
(1)。您可以阅读 findall/3
因此声明:“找到 [First Argument] 的所有值,使得 [Conditions in Second Argument] 成立,并将这些值放入列表 [Third Argument]”。我用过
findall/3
写谓词rotate_grid(+Grid, ?RotatedGrid)
.这是我在谓词中使用的近似 Haskell-Prolog 等价的列表;每行显示 Haskell 表达式将计算的值与具有相同值的 Prolog 变量之间的关系:a <- [0..3]
= A
在 between(0, 3, A)
b <- [0..3]
= B
在 between(0, 3, B)
(a + 4 * d)
= X
在 X is A + 4 * D
<Grid> !! <Index>
= Element
在 nth0(Index, Grid, Element)
然后我们只需要找到
Element
的所有值:rotate_grid(Grid, RotatedGrid) :-
findall( Element,
( between(0,3,A),
between(0,3,B),
Index is A + 4 * B,
nth0(Index, Grid, Element) ),
RotatedGrid
).
为了验证这是否产生了正确的转换,我对问题中的 Prolog 代码进行了缩减,并提出了以下查询:
?- rotate_grid([t0,t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14,t15],
[t0,t4,t8,t12,t1,t5,t9,t13,t2,t6,t10,t14,t3,t7,t11,t15]).
| true.
脚注:
(1):
between/3
实际上不是 [m..n]
的类似物,因为后者从 m
返回值列表至n
在哪里 between(M,N,X)
将在回溯时使用 M 和 N(包括)之间的每个值来实例化 X。要获取 SWI-Prolog 中的数字列表,我们可以使用 numlist(M,N,Ns)
.所以更严格的类比 x <- [1.10]
将是连词 member(X, Ns), numlist(1, 10, Ns)
.
关于haskell - 将列表理解翻译为 Prolog,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23035186/