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.