Encontre poderes de 2 em uma lista Prolog

Eu estou tentando criar uma lista no Prolog (SWI Prolog) e verificar quais números são potências de 2 e segundo encontrar quantas vezes um número específico está na lista (neste exemplo eu estou tentando encontrar quantas vezes o número 3 está na lista). Por exemplo, se você perguntar

?- check([0,2,3,-5,-2,1,8,7,4], MULT2, THREE). 

Você deveria ver

 MULT2=[2,8,4] THREE=1 

Minha primeira tentativa de encontrar uma solução é procurar na lista com head e fazer head mod 2 = 0 para encontrar todos os números que são potências de 2, mas algo deu errado e eu só recebo “false” como resposta.

Veja como você pode encontrar os “poderes de dois” de maneira logicamente pura!

Usando o sicstus-prolog 4.3.5, library(reif) e library(clpz) :

 : - use_module ([ biblioteca (reif) , biblioteca (clpz) ]).

 power_of_two_t (I, T): -
    L # = min (I, 1),
    M # = I / \ (I-1),
    chamada ((L = 1, M = 0), T).  % usando (=) / 3 e (',') / 3 da biblioteca (reif)

Exemplo de consulta 1 usando o tfilter/3 predicados de tfilter/3 em combinação com power_of_two_t/2 :

 ?- tfilter(power_of_two_t, [0,2,3,-5,-2,1,8,7,4], Ps). Ps = [2,1,8,4]. % succeeds deterministically 

Aqui está uma consulta mais geral sugerida por um comentário:

 ?- tfilter(power_of_two_t, [X], Ps). Ps = [X], 0#=X/\_A, _A+1#=X, X in 1..sup, _A in 0..sup ; Ps = [], dif(_A,0), _A#=X/\_B, _B+1#=X, X in 1..sup, _B in 0..sup ; Ps = [], dif(_A,1), _A#=min(X,1), _B#=X/\_C, _C+1#=X, X#>=_A, _A in inf..1. 

Nota de rodapé 1: As seqüências de resposta mostradas acima foram escovadas para indicar o determinismo das chamadas.

Nota de Rodapé 2: Para reproduzir os resultados use call_det/2 que é definido assim:

 call_det (G_0, Det): -
    call_cleanup (G_0, Flag = set),
    (nonvar (bandeira)
    -> Det = true
    ;  Det = false
    ).

É uma coisa estranha ter duas tarefas tão diferentes para fazer em um predicado. Você provavelmente deve ter dois predicados separados, um para contar o número de potências de 2 e um para contar 3s. Então você pode combiná-los em um predicado como:

 check(Nums, MULT2, THREE) :- count2powers(Nums, MULT2), count3s(Nums, THREE). 

Depois disso, você pode se decompor ainda mais e ter um predicado separado para verificar se um número é uma potência de 2:

 is2power(1). is2power(N) :- N > 0, N2 is N // 2, N2 * 2 =:= N, is2power(N2). 

Esta é uma engenharia básica de software e desta forma você pode construir seu programa passo a passo e você será capaz de fazer perguntas mais concretas e significativas do que apenas “O programa inteiro retorna falso”.