Home > Net >  How to structure the state in activityOf() in CodeWorld?
How to structure the state in activityOf() in CodeWorld?

Time:10-27

I explore the usage of activityOf(state_0, change, picture) in CodeWorld framework. The state is described as a tuple. I test the possibility to let one of the elements in the tuple to be a list, since I think that would be very useful and make coding more compact.

In the example below I show that it seems to work if I just print out the first element u1 in the u_list. I can control the value by keys for up and down and time t goes on. The second element u2 in the u_list is simply there and not changed.

program = activityOf(state_0, change, picture)
state_0(rs) = (t0, u_list_0)

u_list_0 = [u10,u20]
t0 = 0
u10 = 0
u20 = 7

t_of((t_value,_)) = t_value
u1_of((_, ulist)) = ulist#1 
u2_of((_, ulist)) = ulist#2

change((t, u_list), KeyPress("Up"))    = (t_of((t,u_list)), [u1_of((t, u_list)) 1])
change((t, u_list), KeyPress("Down"))  = (t_of((t,u_list)), [u1_of((t, u_list))-1])
change((t, u_list), TimePassing(dt))   = (t_of((t,u_list)) dt, u_list)
change((t, u_list), other)             = (t, u_list)
picture((t, u_list))                   = pictures [translated(lettering(printed(t_of((t, u_list)))),0,1),
                                                              lettering(printed(u1_of((t, u_list))))]

However, if I change the example on the last row to just print out u2, i.e. change u1_of (..) to u2_of(..) then I get get no compilation error and the program runs. But if I press any of the keys up and down then I get a runtime error for the line 11 of the code where u2_of() is defined.

Error message:

List index is too large.
When evaluating:  error, called  in the standard library  idxErrorTooLarge, called     
in the standard library  #, used at  Line 11, Column 21 in your code

What is going on here? Is it at all possible to use a list as one element in the state tuple?

Link to run https://code.world/#PBKh1Aucqqxg48ePyxxAuUg

CodePudding user response:

In your up and down key handlers, you are changing the list to have only one element:

change((t, u_list), KeyPress("Up"))    = (t_of((t,u_list)), [u1_of((t, u_list)) 1])
change((t, u_list), KeyPress("Down"))  = (t_of((t,u_list)), [u1_of((t, u_list))-1])
                                                            ^^^^^^^^^^^^^^^^^^^^^^

If you ask for the second element of the list (as picture does) after pressing one of those keys, there won't be one to access. You might want something like:

[u1_of((t, u_list))-1, u2_of(t, u_list)]

As a stylistic comment: it's fairly unusual to use accessor functions like this in Haskell if pattern matching gets you where you want to go. For example, this would be a bit more idiomatic:

change ((t, [r, c]), KeyPress "Up"  ) = (t, [r 1, c])
change ((t, [r, c]), KeyPress "Down") = (t, [r-1, c])

This would be much more idiomatic:

data GameState = GameState
    { t :: Int
    , r :: Int
    , c :: Int
    }

change (s, KeyPress "Up"  ) = s { r = r s   1 }
change (s, KeyPress "Down") = s { r = r s - 1 }

One benefit of this final style is that it's not possible to accidentally create a "list" with the wrong number of elements.

  • Related