在我看来,使用DCGs处理字节列表中的二进制数据应该是可行的。然而为了使其通用,必须使用位运算符,这意味着需要使用 is/2
,这也意味着实例化顺序是一个问题,这可能会使DCGs在解析和生成时变得混乱。这里的想法是序列化/反序列化二进制数据,但我认为这个示例足够简单,可以说明问题。
让我用一些代码来说明。假设我有一个二进制协议。我想从一个字节中读取两个4位整数。我的天真尝试如下:
two_four_bit_ints(High, Low) -->
[B],
{
High is B >> 4,
Low is B /\ 0xF
}.
这个似乎适用于解析:
?- phrase(two_four_bit_ints(H,L), [255]).
H = L, L = 15.
?- phrase(two_four_bit_ints(H,L), [0]).
H = L, L = 0.
?- phrase(two_four_bit_ints(H,L), [15]).
H = 0,
L = 15.
?- phrase(two_four_bit_ints(H,L), [240]).
H = 15,
L = 0.
但这并 不会 产生:
?- phrase(two_four_bit_ints(15,15), [X]).
ERROR: is/2: Arguments are not sufficiently instantiated
?- phrase(two_four_bit_ints(15,15), X).
ERROR: is/2: Arguments are not sufficiently instantiated
不确定该怎么做。我准备好有人会大喊“使用clpfd
”,但它似乎不支持位移操作,而且在低级代码中调用如此强大的系统可能会影响性能。
由于我没有看到许多有关二进制的帮助程序,是否有其他更喜欢的方法可以在Prolog中进行二进制提取/编码?目前我只使用SWI,所以我很乐意接受那些不适用于ISO的建议,但如果它是可移植的,那就更好了。我还希望能找到像Erlang的位语法之类的东西,但搜索没有任何运气。
(is)/2
是被调整模式的,但另一方面你又“担心在低级代码中调用如此强大的系统[如clpfd]会产生性能影响”。你必须做出选择。移位与乘法、除法和指数相关... - falseis/2
的局限性。我并不是说我需要is/2
。我是想要解析和生成,而且我怀疑在实践中clpfd
会太重了。如果有证据证明我错了,我很乐意接受。 - Daniel Lyonsclpfd
则完全不会发生这样的错误。 - false