我正在尝试将代码从Haskell重写为Prolog.
count :: Eq a => a -> [a] -> Int
count x = length . filter (x==)
f :: [Integer] -> [Integer]
f [] = []
f list = filter (\x -> count x list == 1) list
Run Code Online (Sandbox Code Playgroud)
此代码返回列表包含仅在列表中出现一次的元素.所以如果我有列表[1,1,2,2,3,4,4,5]
这个函数返回[3,5]
我试图在Prolog中找到过滤器构造,但似乎没有这样的事情.如何在Prolog中创建类似的功能?
对于现有的答案,我想添加一个非常通用的答案,你可以在多个方向上使用它.
list_element_number/3
我从以下谓词开始,定义以下关系:
Ls0
E
N
的出现E
在Ls0
这里是:
list_element_number(Ls0, E, N) :- tfilter(=(E), Ls0, Ls), length(Ls, N).
此解决方案使用tfilter/3
from library(reif)
.谓词包含count
您发布的函数.这个谓词相对于函数的主要好处是谓词不仅可以用于那些甚至Haskell都可以轻松完成的情况,例如:
?- list_element_number([a,b,c], a, N). N = 1.
不,我们也可以在其他方向使用它,例如:
?- list_element_number([a,b,c], X, 1). X = a ; X = b ; X = c ; false.
甚至:
?- list_element_number([a,b,E], X, 2). E = X, X = a ; E = X, X = b ; false.
甚至:
?- list_element_number([A,B,C], X, 3). A = B, B = C, C = X ; false.
甚至在最常见的情况下,所有参数都是新变量:
?- list_element_number(Ls, E, N). Ls = [], N = 0 ; Ls = [E], N = 1 ; Ls = [E, E], N = 2 ; Ls = [E, E, E], N = 3 .
我们可以公平地列举所有这样的答案:
?- length(Ls, _), list_element_number(Ls, E, N). Ls = [], N = 0 ; Ls = [E], N = 1 ; Ls = [_160], N = 0, dif(E, _160) ; Ls = [E, E], N = 2 .
list_singletons/2
使用这个构建块,我们可以定义list_singletons/2
如下:
list_singletons(Ls, Singles) :- tfilter(count_one(Ls), Ls, Singles). count_one(Ls, E, T) :- list_element_number(Ls, E, Num), cond_t(Num=1, true, T).
这使用cond_t/3
和(再次)tfilter/3
来自library(reif)
.
以下是一些示例查询.首先,您发布的测试用例:
?- list_singletons([1,1,2,2,3,4,4,5], Singles). Singles = [3, 5].
它按预期工作.
现在涉及变量的案例:
?- list_singletons([A,B], Singles). A = B, Singles = [] ; Singles = [A, B], dif(A, B).
在回溯时,会生成所有可能性:要么 A = B
保持,要么在这种情况下,没有任何元素只出现一次.或者 A
是不同的 B
,在这种情况下,两个A
和B
出现一次.
作为上述查询的特例,我们可以发布:
?- list_singletons([A,A], Singles). Singles = [].
作为概括,我们可以发布:
?- length(Ls, _), list_singletons(Ls, Singles). Ls = Singles, Singles = [] ; Ls = Singles, Singles = [_7216] ; Ls = [_7216, _7216], Singles = [] ; Ls = Singles, Singles = [_7828, _7834], dif(_7828, _7834) ; Ls = [_7216, _7216, _7216], Singles = [] ; Ls = [_7910, _7910, _7922], Singles = [_7922], dif(_7910, _7922) .
享受这种关系的普遍性,通过逻辑纯度获得.