0

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

janpeter
  • 681
  • 8
  • 22
  • Probably lists are 0-indexed, so you want `ulist#0` and `ulist#1`. – Daniel Wagner Oct 25 '21 at 15:04
  • No the list are not 0-indexed. You also see that if run the code above that you see u1=0 on the screen and above time running. The function change() has some internal structure that I have not insight in. I suspect it just read the first element in the list and take that as if was an element in the tuple of its own, sort of. Hope someone with more insight into CodeWorld or Haskell can give some clue. – janpeter Oct 25 '21 at 15:43
  • 1
    Is there a reason you want to keep `u_list_0, t0, u10, u20, t_of, u1_of, u2_of`? If you remove then, it is much easier to see what is going on: https://code.world/#P_DurqLvl1lPnI01pfW_65A – Micha Wiedenmann Oct 25 '21 at 15:58
  • I think your simplification is ok with me. If you change the last ulist#1 to list#2 you get the same problem as I am talking about. The purpose of the this example is just to investigate whether I can replace an element in state with a list that contain several numbers. A tuple is "allowed" to have any object and also a list. But very uncertain if the function change() is designed to handle a tuple with an element that is a list. So since a tuple in principle can have an element that is a list I do not get compilation error. But likely the CodeWorld design of change() does not handle this. – janpeter Oct 25 '21 at 16:08

1 Answers1

2

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.

Daniel Wagner
  • 145,880
  • 9
  • 220
  • 380
  • Surprise to me that my code change the size of u_list. Then the problem is on my side and not on those who designed change()... You see the reason for my which to structure state in a tuple of separate lists if you go to my other recent post on CodeWorld. Here I have a long tuple I call state_and_table and the code could clearly be improved to be scaled up. And that is what I try to investigate here. – janpeter Oct 25 '21 at 16:38
  • I would like to see how my original code should be modified so that u_list is NOT changed in size. The idea of u1_of() and u2_of() is just to address the element of interest and keep the rest. I am a beginner of Haskell and find it difficult to relate to your code. – janpeter Oct 25 '21 at 16:58
  • @janpeter I included an example in this answer of how the original code needs to be modified so that `u_list` is not changed in size -- in two alternative ways, even. (...didn't I? Or I have I misunderstood your request somehow?) – Daniel Wagner Oct 25 '21 at 18:03