Sto provando a scrivere una soluzione per AdventCode il giorno 6 in Prolog. (http://adventofcode.com/day/6)Questo codice è ricorsivo in coda?
In precedenza ho scritto una soluzione che creava dinamicamente e sostituiva i predicati, per tenere traccia delle luci. Non sorprende che sia piuttosto lento, così ho deciso di provare a scriverlo usando uno stile più "funzionale"; Creare una lista contenente tutte le luci, quindi manipolare quella lista.
Sto provando a costruire la lista iniziale, che consisterebbe di un milione di elementi, ognuno un termine light(X, Y, Status)
. Ho pensato di iniziare con una lista [light(0, 0, off)]
, quindi anteporre nuovi termini ad essa. Per fare ciò, osservo il primo elemento dell'elenco, quindi determina quale dovrebbe essere il prossimo elemento, quindi anteponilo. Ripetere.
Ho un predicato next_light/2
che prende una luce e determina quale dovrebbe essere la luce successiva (da anteporre). Se non più luci devono essere aggiunti, restituisce done
:
next_light(light(X, Y, _), NextLight) :-
X < 999,
NextX is X + 1,
NextLight = light(NextX, Y, off).
next_light(light(999, Y, _), NextLight) :-
Y < 999,
NextY is Y + 1,
NextLight = light(0, NextY, off).
next_light(light(999, 999, _), done).
Poi ho tentativo di costruire la lista con questo codice:
init_lights(Lights) :-
gen_lights([light(0, 0, off)], Lights).
gen_lights(Lights, AllLights) :-
[Light|_] = Lights,
next_light(Light, NextLight),
add_light(Lights, NextLight, AllLights).
add_light(Lights, done, Lights).
add_light(Lights, NextLight, AllLights) :-
gen_lights([NextLight|Lights], AllLights).
Tuttavia, quando corro init_lights(L)
in SWI-Prolog, I ottieni "ERRORE: Fuori dallo stack locale". Quindi c'è un overflow dello stack, ma quando guardo il codice, sembra coda ricorsiva per me. add_light
e gen_lights
sono reciprocamente ricorsivi; non sono sicuro se questo è un problema.
Ho provato a ispezionare le chiamate con il debugger, ma a quanto pare SWI-Prolog disabilita l'ottimizzazione delle chiamate tail quando si utilizza trace
, quindi non è stato d'aiuto.
(Per la cronaca, quando ho cambiato il codice per utilizzare 3 anziché 999 come la coordinata massima, init_lights(L)
sembrava produrre l'elenco corretto, e non appendere o causare un overflow dello stack.)
I probabilmente sto trascurando qualcosa, ma non lo vedo. Qualche consiglio benvenuto!^_^
if-then-else funziona se tutti i casi problematici vengono gestiti con errori di istanziazione. – false
In questo caso particolare, non mi interessa molto delle proprietà dichiarative. :) Ho messo un '!' Dopo 'X <999' in' next_light/2', e il problema è svanito. Grazie! –
@HermanvanBelaster. Fai attenzione alle soluzioni rapide! È nella loro natura sostituire un problema che si può vedere con due problemi che non si possono vedere ...(fine della predica :) – repeat