[mercury-users] Learning Mercury
Ralph Becket
rafe at csse.unimelb.edu.au
Mon Aug 13 09:15:14 AEST 2007
Hi Tom,
I've attached a working version of your planner. There are a few points
worth observing:
Tom Davies, Saturday, 11 August 2007:
> :- module monkey.
> :- interface.
> :- import_module io.
> :- pred main(io::di, io::uo) is det.
main has to have determinism cc_multi ("committed choice with multiple
solutions"), not det ("exactly one solution").
> :- implementation.
> :- import_module bool.
> :- type horizontal_t ---> door; middle; window.
> :- type vertical_t ---> onbox; onfloor.
> :- type state_t --->
> state(
> monkeyHorizontal::horizontal_t,
> monkeyVertical::vertical_t,
> boxHorizontal::horizontal_t,
> hasBanana::bool
> ).
> :- type action_t ---> grasp; climb; push
> (bfrom::horizontal_t,bto::horizontal_t);
> walk(mfrom::horizontal_t,mto::horizontal_t).
>
> :- pred move(state_t,action_t,state_t).
> :- mode move(in,out,out) is nondet.
>
> move(
> state(middle, onbox, middle, no),
> grasp,
> state(middle, onbox, middle, yes)
> ).
>
> move(
> state(P, onfloor, P, H),
> climb,
> state(P, onbox, P, H)
> ).
>
> move(
> state(P1, onfloor, P1, H),
> push(P1,P2),
> state(P2, onfloor, P2, H)
> ).
>
> move(
> state(P1, onfloor, B, H),
> walk(P1, P2),
> state(P2, onfloor, B, H)
> ).
>
> :- pred canget(state_t).
> :- mode canget(in) is nondet.
This mode declaration doesn't make sense: a predicate with only input
arguments can have at most one solution for any given input, hence
this should have determinism semidet.
> canget(state(_,_,_,yes)).
>
> canget(S1) :-
> move(S1,Move,S2),
> canget(S2).
This planning algorithm is almost certainly going to get you into a
loop!
> main(!IO) :-
> print(canget(state(door, onfloor, window, no)), !IO).
This won't do what you think: canget(state(door, onfloor, window, no))
here is seen as a closure, not a goal.
My code shows you how to get the result you want.
Hope this helps,
-- Ralph
-------------- next part --------------
:- module monkey.
:- interface.
:- import_module io.
:- pred main(io::di, io::uo) is cc_multi.
:- implementation.
:- import_module list.
:- import_module pair.
:- type horizontal ---> door ; middle ; window.
:- type vertical ---> on_box ; on_floor.
:- type has_banana ---> holding_banana ; not_holding_banana.
:- type world_state
---> world_state(
monkey_horizontal :: horizontal,
monkey_vertical :: vertical,
box_horizontal :: horizontal,
has_banana :: has_banana
).
:- type action
---> start
; grasp
; climb
; push(push_from :: horizontal, push_to :: horizontal)
; walk(walk_from :: horizontal, walk_to :: horizontal).
:- type plan == list(pair(action, world_state)).
:- pred move(world_state, action, world_state).
:- mode move(in, out, out) is nondet.
move(
world_state(middle, on_box, middle, not_holding_banana),
grasp,
world_state(middle, on_box, middle, holding_banana)
).
move(
world_state(P, on_floor, P, H),
climb,
world_state(P, on_box, P, H)
).
move(
world_state(P1, on_floor, P1, H),
push(P1, P2),
world_state(P2, on_floor, P2, H)
) :-
horizontal(P2),
P2 \= P1.
move(
world_state(P1, on_floor, B, H),
walk(P1, P2),
world_state(P2, on_floor, B, H)
) :-
horizontal(P2),
P2 \= P1.
:- pred horizontal(horizontal::out) is multi.
horizontal(door).
horizontal(middle).
horizontal(window).
:- pred can_get_banana(world_state::in, plan::in, plan::out) is nondet.
can_get_banana(world_state(_, _, _, holding_banana), RevPlan, RevPlan).
can_get_banana(S1, RevPlan0, RevPlan) :-
move(S1, Action, S2),
% To avoid loops, ensure we never revisit an old state.
not list.member(_PrevAction - S2, RevPlan0),
can_get_banana(S2, [Action - S2 | RevPlan0], RevPlan).
main(!IO) :-
InitialState = world_state(door, on_floor, window, not_holding_banana),
RevPlan0 = [start - InitialState],
( if can_get_banana(InitialState, RevPlan0, RevPlan) then
Plan = list.map(pair.fst, list.reverse(RevPlan)),
io.write_list(Plan, "\n", io.print, !IO),
io.nl(!IO)
else
io.print("no solution\n", !IO)
).
More information about the users
mailing list