[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