Search code examples
prolog

Building a list of float achieved with "Type error: `character' expected, found `0.0' (a float)"


I'm trying to initialize the list [ 0.0, 0.17, 0.33, 0.5, 0.67, 0.83, 1] with the following code:

#!/usr/bin/swipl

floorsMax( 6 ).

floorLocations( _, 0, TmpLocs, Locs ) :-
    Locs is [0.0 | TmpLocs ].
floorLocations( FloorsMax, FloorsCount, TmpLocs, Locs ) :-
    Loc is FloorsCount / FloorsMax,
    Count is FloorsCount - 1,
    floorLocations( FloorsMax, Count, [Loc|TmpLocs], Locs ).
floorLocations( Locs ) :-
    floorsMax( FloorsMax ),
    trace,
    floorLocations( FloorsMax, FloorsMax, [], Locs ).

The executions steps are:

?- floorLocations(Fl).
   Call: (11) floorLocations(6, 6, [], _2732) ? creep
   Call: (12) _3158 is 6/6 ? creep
   Exit: (12) 1 is 6/6 ? creep
   Call: (12) _3264 is 6+ -1 ? creep
   Exit: (12) 5 is 6+ -1 ? creep
   Call: (12) floorLocations(6, 5, [1], _2732) ? creep
   Call: (13) _3410 is 5/6 ? creep
   Exit: (13) 0.8333333333333334 is 5/6 ? creep
   Call: (13) _3522 is 5+ -1 ? creep
   Exit: (13) 4 is 5+ -1 ? creep
   Call: (13) floorLocations(6, 4, [0.8333333333333334, 1], _2732) ? creep
   Call: (14) _3668 is 4/6 ? creep
   Exit: (14) 0.6666666666666666 is 4/6 ? creep
   Call: (14) _3780 is 4+ -1 ? creep
   Exit: (14) 3 is 4+ -1 ? creep
   Call: (14) floorLocations(6, 3, [0.6666666666666666, 0.8333333333333334, 1], _2732) ? creep
   Call: (15) _3926 is 3/6 ? creep
   Exit: (15) 0.5 is 3/6 ? creep
   Call: (15) _4038 is 3+ -1 ? creep
   Exit: (15) 2 is 3+ -1 ? creep
   Call: (15) floorLocations(6, 2, [0.5, 0.6666666666666666, 0.8333333333333334, 1], _2732) ? creep
   Call: (16) _4184 is 2/6 ? creep
   Exit: (16) 0.3333333333333333 is 2/6 ? creep
   Call: (16) _4296 is 2+ -1 ? creep
   Exit: (16) 1 is 2+ -1 ? creep
   Call: (16) floorLocations(6, 1, [0.3333333333333333, 0.5, 0.6666666666666666, 0.8333333333333334, 1], _2732) ? creep
   Call: (17) _4442 is 1/6 ? creep
   Exit: (17) 0.16666666666666666 is 1/6 ? creep
   Call: (17) _4554 is 1+ -1 ? creep
   Exit: (17) 0 is 1+ -1 ? creep
   Call: (17) floorLocations(6, 0, [0.16666666666666666, 0.3333333333333333, 0.5, 0.6666666666666666, 0.8333333333333334, 1], _2732) ? creep
   Call: (18) _2732 is [0.0, 0.16666666666666666, 0.3333333333333333, 0.5, 0.6666666666666666, 0.8333333333333334, 1] ? creep
ERROR: Type error: `character' expected, found `0.0' (a float)
ERROR: In:
ERROR:   [18] _214 is [0.0,0.16666666666666666|...]
ERROR:   [17] floorLocations(6,0,[0.16666666666666666,0.3333333333333333|...],_258) at /home/aubin/Dev/IA/prolog-Ascenseur/Stimulus.pl:7
ERROR:   [16] floorLocations(6,1,[0.3333333333333333,0.5|...],_300) at /home/aubin/Dev/IA/prolog-Ascenseur/Stimulus.pl:11
ERROR:   [15] floorLocations(6,2,[0.5,0.6666666666666666|...],_342) at /home/aubin/Dev/IA/prolog-Ascenseur/Stimulus.pl:11
ERROR:   [14] floorLocations(6,3,[0.6666666666666666,0.8333333333333334|...],_384) at /home/aubin/Dev/IA/prolog-Ascenseur/Stimulus.pl:11
ERROR:   [13] floorLocations(6,4,[0.8333333333333334,1],_426) at /home/aubin/Dev/IA/prolog-Ascenseur/Stimulus.pl:11
ERROR:   [12] floorLocations(6,5,[1],_468) at /home/aubin/Dev/IA/prolog-Ascenseur/Stimulus.pl:11
ERROR:   [11] floorLocations(6,6,[],_504) at /home/aubin/Dev/IA/prolog-Ascenseur/Stimulus.pl:11
ERROR:   [10] floorLocations(_528) at /home/aubin/Dev/IA/prolog-Ascenseur/Stimulus.pl:15
ERROR:    [9] toplevel_call(user:user: ...) at /usr/lib/swi-prolog/boot/toplevel.pl:1113
   Exception...

The trace is good, the intermediate result is as expected but the final assignment doesn't work, why?

EDIT after reading the good advices by damianodamiano, here is a solution (with a cut, sorry for the purists):

floorLocations( _, 0, TmpLocs, [0.0 | TmpLocs ] ) :- !.
floorLocations( FloorsMax, FloorsCount, TmpLocs, Locs ) :-
    FloorsCount > 0,
    Loc is FloorsCount / FloorsMax,
    Count is FloorsCount - 1,
    floorLocations( FloorsMax, Count, [Loc|TmpLocs], Locs ).
floorLocations( Locs ) :-
    floorsMax( FloorsMax ),
    floorLocations( FloorsMax, FloorsMax, [], Locs ).

Solution

  • This happens because is/2 is used to evaluate mathematical expressions, but [0.0 | TmpLocs ] is not a mathematical expression. To fix your code, you need to write something like:

    floorLocations( _, 0, TmpLocs, [0.0 | TmpLocs ] ).
    

    instead of

    floorLocations( _, 0, TmpLocs, Locs ) :-
        Locs is [0.0 | TmpLocs ].
    

    in this way, you will have the whole list. Furthermore, there is a problem with your code. If you ask the first solution, you will get the answer you expect.

    Fl = [0.0, 0.16666666666666666, 0.3333333333333333, 0.5, 0.6666666666666666, 0.8333333333333334, 1]
    

    But there is a choice point open and more solutions available. What happens if we ask for a second solution? The program loops forever, and eventually finishes the memory. This because the value of FloorsCount gets negative and so there is not a termination for the recusion. To fix this, simply add FloorsCount > 0 as first check in the second floorLocations/4 clause.