Sto costruendo un parser e un generatore per date e orari. In un normale linguaggio di programmazione questi sarebbero scritti separatamente. In Prolog + CLP (FD) posso scrivere un predicato che fa entrambi :-)Vincolo non propagato all'istanziazione dei membri dell'elenco
Nel mio caso di utilizzo ha spesso senso analizzare un numero di cifre e convertirlo in un numero intero o generare un numero di cifre basato su un dato numero intero.
Il mio problema è che clpfd:run_propagator/2
non viene chiamato quando le singole cifre vengono istanziate, nonostante le mie dichiarazioni che utilizzano clpfd:init_propagator/2
. C'è un modo per fare questo o sto commettendo un errore nella mia definizione di clpfd_digits/2
?
codice implementato in SWI-Prolog:
:- use_module(library(apply)).
:- use_module(library(clpfd)).
:- multifile(clpfd:run_propagator/2).
day(D) --> {clpfd_digits(D, [D1,D2])}, digit(D1), digit(D2).
digit(D) --> [C], {code_type(C, digit(D))}.
clpfd_digits(N, Ds):-
clpfd:make_propagator(clpfd_digits(N, Ds), Prop),
clpfd:init_propagator(N, Prop),
clpfd:init_propagator(Ds, Prop),
forall(
member(D, Ds),
clpfd:init_propagator(D, Prop)
),
clpfd:trigger_once(Prop).
clpfd:run_propagator(clpfd_digits(N, Ds), MState):-
( maplist(is_digit0, Ds)
-> clpfd:kill(MState),
digits_to_nonneg(Ds, N)
; integer(N)
-> clpfd:kill(MState),
nonneg_to_digits(N, Ds)
; true
).
digits_to_nonneg([], 0):- !.
digits_to_nonneg(Ds, N):-
maplist(char_weight, Chars, Ds),
number_chars(N, Chars).
char_weight(Char, D):-
char_type(Char, digit(D)).
nonneg_to_digits(0, []):- !.
nonneg_to_digits(N, Ds):-
atom_chars(N, Chars),
maplist(char_weight, Chars, Ds).
is_digit0(D):- integer(D), between(0, 9, D).
Esempio di utilizzo:
?- string_codes("12", Cs), phrase(day(D), Cs).
Cs = [49, 50],
clpfd_digits(D, [1, 2]).
Come si può vedere il vincolo non viene calcolato per ricavare il valore di D
.
Vedere [questa risposta] (http://stackoverflow.com/a/28442760/772868) per il modo clpfd per risolvere un problema correlato. – false
Cosa ti aspetti di guadagnare rispetto a 'when ((ground (Codes); nonvar (N)), number_codes (N, Codes))'? Entrambi sono deboli e non le relazioni - del resto. – false
@false Questo è abbastanza vicino! Tuttavia non tratta gli zeri di riempimento, ad esempio 'frase (giorno (2)," 02 ")'. –