mapRec( Pred, Arg, OutArg ) :-
% tworzymy nowy predykat pomocniczy
gensym( partial, UNIQ ),
Left =.. [ UNIQ, X, Y ],
PartialMapRec = ( Left :- mapRec( Pred, X, Y ) ),
asserta( PartialMapRec, Ref ),
% rozkładamy term wejściowy
Arg =.. [ Comp, Op | Args ],
map( UNIQ, Args, Args2 ), % dla termów atomowych mamy podstawę indukcji: map nic nie robi na pustej liście
% składamy term ponownie
Arg2 =.. [ Comp, Op | Args2 ],
% aplikujemy Pred i zwracamy wynik
F =.. [ Pred, Arg2, OutArg ],
F,
erase( Ref ), % kasujemy predykat pomocniczy
!.
mapRec( _, Arg, Arg ) :-
write( final ), write(' '), write( Arg ), nl,
final( Arg ), !.
Najogólniej rzecz biorąc, nie działała ona tak jak powinna. To znaczy coś tam niby liczyła, ale źle, a co gorsze była okropnie długa (jak widać) i beznadziejna do debugowania. Ponadto wymagała ingerencji w bazę predykatów Prologa, co jest moim zdaniem brzydkie i psuje trochę wydajność. Zakończyłem nieudaną sesję programistyczną mocno zniesmaczony Prologiem, a konkretnie jego odpornością na próby metaprogramowania.
Dzisiaj jednak dokopałem się do paru predykatów, które znacząco uprościły konstrukcję mapRec'a:
mapRec( Pred, Arg, OutArg ) :-
Arg =.. [ Comp, Op | Args ],
maplist( mapRec( Pred ), Args, Args2 ),
Arg2 =.. [ Comp, Op | Args2 ],
apply( Pred, Arg2, OutArg ),
!.
mapRec( _, Arg, Arg ) :-
write( final ), write(' '), write( Arg ), nl,
final( Arg ), !.
Nie taki Prolog straszny jak go malują :-)
Bazując na poznanej wiedzy napisałem wreszcie simp'a, czyli predykat upraszczający wyrażenia arytmetyczne. Jest to jedno z zadań na pracownię z Programowania w Logice. Wyszedł niedługi i raczej nie ma zbyt wielu błędów :-) Leży tutaj.
Do uruchomienia potrzebny jest interpreter Prologa. Ja używam SWI-Prologa, ale program powinien działać na każdym sensownym interpreterze.
Dla tych którzy nie mieli nigdy doczynienia z Prologiem, oto jak wygląda przykładowa sesja:
?- [simp].
% simp compiled 0.00 sec, 11,264 bytes
Yes
?- simp( x-x, EXP ).
EXP = 0 ;;
No
?- simp( x-x*1*2*3, EXP ).
EXP = x* -5 ;;
No
?- simp( 1*2*(1+1+1)*x-x*1*2*3, EXP ).
EXP = 0 ;;
No
?- simp( x*(y+z*(1+p)-p*(x-z)), EXP ).
EXP = - (p* (x*x))+ (p* (x*z)*2+ (x*y+x*z)) ;;
No
?-
% halt
Choć Prolog bywa wkurzający, to jednak przyjemnie jest nauczyć się czegoś nowego.
Brak komentarzy:
Prześlij komentarz