Archive for the 'Ocaml humps' Category

Functional programming & immutable objects explained — IRC style

Saturday, February 23rd, 2008

I was on #ocaml channel on irc.freenode.org. (btw - freenode hosts channels for a lot of popular languages and technologies). This was a while back when I started making OCaml SDL examples that you can find on this blog. I think this short IRC chat told me more about FP than anything I read before.

<middayc-> when I read about FP I read that things should be immutable and that there should be little state or side effects… but if I am making a game I need states all around the place … a trivial example, I need an x,y and velocity vector of every bullet, particle effect, main character, enemies with more states regarding to their behaviour .. etc… is this ok then or I don’t get something

<hcarty> For the velocity vector example - one way to think about it would be to have your update function return a new “bullet” rather than modifying the old one.

<hcarty> But it’s a style choice, and OCaml lets you have it both ways

<middayc-> :) that is an interesting view (new bullet every time)

<Yoric[DT]> But OCaml is often able to optimize this “create a new bullet each time” to “reuse the same bullet”.

<RobertFischer> middayc- Whenever possible, use many small, rapidly-GC’ed data elements.

<RobertFischer> Ocaml is highly optimized for that kind of behavior.

<RobertFischer> All of your ex-Java (or whatever) training which says that “object creation is expensive” needs to go out the window.

<RobertFischer> You’re generally best off using records or tuples (as appropriate) and minimizing the amount of mutable data you have. This will give you the best performance in Ocaml.

<middayc-> aha … yes I was thinking about GC in that way

<RobertFischer> Thinking in terms of list/graph processing instead of message passing is also a major performance improvement.

<RobertFischer> So, when you have a bunch of sprites and a change in the moment in time, don’t think of telling each and every sprite to update itself — that’s the OO way to approach the problem.

<ita> does the use of closures instead of classes change anything speed-wise?

<middayc-> huh I have no idea what is list/graph processing …

<RobertFischer> Do you know what a graph is?

<middayc-> no

<RobertFischer> A graph is a data structure of data structures.

<middayc-> aha .. like a tree

<middayc-> like list is flat — a graph is structured?

<RobertFischer> Yes, where each node is a data structure. So a list of lists, a tree of lists, a tree of maps of lists of map-list tuples.

<RobertFischer> Whatever.

<ita> middayc-: {vertex, arcs}

<middayc-> aha … I begin to understand what you mean by list/graph processing vs object.update()

<RobertFischer> The more you can just tell OCaml (or any FP language), “Here’s how to process each element of that graph, and here’s the graph to process”, the better off you’ll be. See fold and iter of examples of that.

<middayc-> cool … you should write a book … you explain it in a way I can quickly understand

<RobertFischer> If you think of your state as a graph of elements, and can define a function which changes your state and returns the new graph of elements, then you’re going to be digging around at the best performance in Ocaml.

<RobertFischer> I’m doing a podcast and writing a blog.

<RobertFischer> I’ll work on a book later. :-D

<middayc-> aha … a new graph each time?

<middayc-> I have to invert my brain from stuff I am used to and then it all makes sense

<RobertFischer> Pretty much.

Thanks guys for explaining it to me so well! Since then I wrote 3 examples of using SDL with OCaml and I used no mutable state and felt no need to use it. I like the code I wrote with this paradigm a lot. I will continue building a game in OCaml and see what happens next.

Ocaml: mini SDL example v3

Thursday, January 24th, 2008

This is the 3rd iteration of OCaml SDLCaml game example that I make and learn OCaml at the same time. Changes are:

  • keyboard input as it should be (multiple keys at the same time, diagonal speed same as orthogonal)
  • ship shoots bullets (ctrl)
  • very dumb enemy space ships besides rocks
  • a scene record that holds all elements of the scene

Few codebits. Here we define the scene record and a function that creates an empty scene.

type scene = { ship: ship ; bullets : particle list ; rocks : particle list;  aliens : particle list; }
let empty_scene = { ship = {poss = (vec2 0 0); shoot_count = 0} ; bullets = [] ; rocks = [] ; aliens = [] }

This functions handle bullets. First updates each bullet and second one looks at a key-map and creates new bullets if needed.

let update_bullets r = { r with pos = r.pos +| r.vel }
let make_bullets bullets keys ship_pos =
	match keys.shoot with
		| 0 -> bullets;
		| _ -> { pos = ship_pos +| vec2 16 16 ; vel = vec2 12 0 ; size = 5 } :: bullets

If you are asking yourself what is +| - it is a vector operator (infix function). We defined it like this.

let ( +| ) a b = {x = a.x + b.x; y = a.y + b.y}

Click here to see the full source

Again thanks a lot to all who commented and suggested code improvements on #ocaml IRC channel. Especially asmanur suggested a lot of great improvements.

Ocaml: mini SDL example 2

Sunday, January 13th, 2008

Images residue in an array now, we passed them around individually before. This is how we load and free them.

let load_images () =
	[|
		load_image "data/background.bmp" ;
		load_image "data/ship.bmp" ;
		load_image "data/rock1.bmp" ;
	|]
;;

let free_surfaces images = Array.iter (function(img) -> free_surface img) images;;

game screenshot

Input is better handeled now. Ship moves while you hold the appropriate arrow key down. But it is not as it should be at the end. If you start pressing more than 1 keys at once it won’t work as expected.

Rocks have been added. They are records that residue in a list. Those two functions are used for drawing and calculating/making the new rock. The power that OCaml gives you with records shows here a little.

let draw_rocks screen images (r:particle) =
      let { pos = p } = r in apply_surface p images.(2) screen;;

let update_rocks (r:particle) =
      { r with pos = if r.pos.x > (-r.size) then r.pos +| r.vel else (vec2 650 r.pos.y) } ;;

That +|is an operator we defined. It represents the addition of two vectors. Vectors and this operator are defined in 3 lines of code.

type vec2 = { x: int; y: int };;
let vec2 x y = {x=x; y=y};;

let ( +| ) a b = {x = a.x + b.x; y = a.y + b.y}

Click to look at the source code.

I warn you however. I am learning OCaml as I type this and this is the first time I use SDL also. If you notice any mistakes or stupidities let me know. I am still proud (and surprised) that there is no mutable or global stuff in the code. Basically one chat on the IRC hinted me how I should think in FP at all, much better than anything I read before, and it worked so far. I intend to post that IRC chat here soon.

Thanks to bluestorm on #ocaml IRC for proposing few improvements to the code. It has been updated.

Compiling Ocaml, SDL and OpenGL on Windows (mini tutorial)

Monday, January 7th, 2008

One of two ways to get OpenGL into Ocaml is by using GLCaml binding. It is up to date and alive. GLCaml also includes so called compact drop-in binding for SDL SDLCaml. I am not much of a low level guy so I had real trouble figuring out how to compile the thing on windows and almost gave up. But the author replied to my mail and gave me few crucial hints which made it all work.

NeHe tutorial number 9 in GLCaml

Here is what to do:

  1. Download and install Ocaml for windows (the MingW version)
  2. Install MingW. Install at least the C package, but NOT make.
  3. Install MSys (also from MingW site) which also installs its own make.
  4. Install the SDL library for mingw. Unzip and copy it to appropriate folders in mingw or make sure mingw can find it.
  5. Unzip glcaml.zip somewhere, and go to that location with MSys shell. When you are there run make in MSys.
  6. All examples should compile (the binding has many SDL and OpenGL) examples.

Thanks to Elliot for making the binding and replying to my mail. I hope I will dig Ocaml and make something concrete with it and this binding. Here is some more info and screens GLCaml and SDLCaml.

Enjoy the camel ride!