
:- module(goedel,[ goedel/2 ], []).

/*
:- pred goedel(T,N) :: ground * num
	# "@var{N} is the goedel number of @var{T}.".
:- pred goedel(T,N) :: nonground * var.

Note that N is an integer, although in float point representation!!
*/

:- use_module(library(lists),[length/2]).
:- use_module(library(numlists),[get_primes/2]).

goedel(T,N):-
	ground(T), !,
	goedel_(T,N).
goedel(_,_).

goedel_(T,N):-
	atomic(T), !,
	name(T,L),
	odd_numbers(L,Odds),
	( Odds = [N] -> true
	; goedel_number(Odds,N)
	).
goedel_(T,N):-
	T =.. TList,
	hash_list(TList,NList),
	goedel_number(NList,N).

hash_list([],[]).
hash_list([X|Xs],[N|Ns]):-
	goedel_(X,N),
	hash_list(Xs,Ns).

goedel_number(List,N):-
	length(List,L),
	get_primes(L,PList),
	prod_of_pows(PList,List,1,N).

prod_of_pows([],[],N,N).
prod_of_pows([Pr|Prs],[Po|Pos],N0,N):-
	N1 is N0*(Pr**Po),
	prod_of_pows(Prs,Pos,N1,N).

odd_numbers([],[]).
odd_numbers([N|Ns],[O|Os]):-
	O is 2*N+1,
	odd_numbers(Ns,Os).
