benefits of learning haskell

March 13, 2010

it’s been said that learning lisp makes you a better programmer, even if you never use the language[who?].

that’s because if you’re used to c/c++/java/etc., lisp introduces the idea of code as data, and encourages a functional style.
in the case of clojure, it also gets you thinking about concurrency, and pushes the functional thing further.

haskell is a different beast entirely.
it also has plenty of foreign concepts to wrap your head around, but the difference is that you’ll be knee-deep in research papers within a day of writing your first “hello world” program.
and if you want to know how that “hello world” program works, you’ll need to read a paper.

point sprites (clojure/penumbra/glsl)

February 24, 2010

this post is partly to inform others, and partly for my own reference when i forget how to do it.

in opengl, it’s common to want to draw a sprite aligned with the viewport.
the naive method is to use a textured quad, but that has some problems:

  • it takes 4 vertices and 4 texture coordinates
  • un-rotating the matrix transformation takes cpu cycles
  • un-rotating the matrix transformation is a pain in the ass

with the point-sprite method, you apply the texture to a point, which is automatically aligned with the viewport,
and only takes one vertex position.
there is built in functionality for point sprites, but a custom shader pair offers more flexibility

implementation

the vertex shader needs to translate and scale the point.
the fragment shader needs to apply the texture.

everything used here is in the penumbra.opengl and clojure.core namespaces.

this bit will set up the inputs for the shader program. one for the window height used in size calculation, and one for the texture to be drawn.

(def declarations
  '((uniform float height)
    (uniform sampler2D tex)))

the vertex shader does the standard matrix transformation to get position, and height/dist^2 for point size.

(def vertex-shader
  '((set! :position (ftransform))
    (set! #^float pos (.xyz :position))
    (set! :point-size (/ height (dot pos pos)))))

the fragment shader just applies the texture based on point coordinates.

(def fragment-shader
  '(;texture the fragment
    (set! :frag-color (texture tex :point-coord))))

this can be made into a program like so:

(def point-sprite-program 
  (create-program declarations vertex-shader fragment-shader))

and used like so:
(assuming window-height and tex are set somewhere. tex should be set with penumbra functions; it’s a struct, rather than a GLuint)

(with-program point-sprite-program
  (uniform height window-height)
  (bind-read :tex tex 0)
  ...body that draws points...)

also, i learned a lesson while cooking this up:
calling gluPerspective with a nevative clip-plane is a fun way to get a black screen.

point-free style (haskell)

February 10, 2010

so, what is point-free style?

point-free style is the art of writing functions without explicitly mentioning local variables.

point-full vs. point-free:

inc x = x + 1
inc = (+ 1)

isn’t that rather pointless?

only in the sense that it lacks points. it can improve code clarity or aid in understanding concepts.
be careful, though, as it can also look like perl if you go overboard with the combinators.

alright, so how do you write point-free functions?

partial application and composition:

curried functions are what makes point-free style so easy in haskell. that first example shows partial application in action.
function composition is also important, so that you don’t have to nest parentheses.

mapcat f xs = concat (map f xs)
mapcat = (.) concat . map

ski:

SKI combinator calculus is a way of representing computations.
the S, K, and I combinators are pretty handy when writing point-free style. they have different names in haskell, but work the same way.

I: id = \x -> x
K: const = \x y -> x
S: (<*>) = \f g x -> f x (g x)

here’s a couple examples:

count = foldl ((+) . const 1) 0
square = (*) <*> id

flip, curry, and uncurry:

flip swaps the position of the first and second arguments.
curry takes a function on a tuple, and makes a function of two arguments from it
uncurry is the inverse of curry: it takes a function with two arguments, and gives a function from a tuple.

flip :: (a -> b -> c) -> (b -> a -> c)
curry :: ((a, b) -> c) -> (a -> b -> c)
uncurry :: (a -> b -> c) -> ((a, b) -> c)

and some examples:

fst = uncurry const
snd = uncurry $ flip const
const = curry fst

functions are monads:

the type ((->) e) is an instance of Monad, which means you can use monad functions on functions.

instance Monad ((->) e) where
  return = const
  (>>=) = flip $ (<*>) . flip

it’s helpful to look at the type of monad functions and substitute (e ->) in for m.

join :: (Monad m) => m (m a) -> m a
join ::  (e -> (e -> a)) -> (e -> a)
join ::  (e -> e -> a) -> e -> a

in the case of functions, join f x = f x x. here’s an obvious use:

square = join (*)

functions are also arrows:

i suspect that if you have looked at arrows, you already know that, though. if not, take a gander here.

there are the arrow composition functions:

(>>>) = flip (.)
(<<<) = flip (>>>)

and pair functions:

fst = \f (x, y) -> (f x, y)
(&&&) = \f g x -> (f x, g x)
(***) = \f g (x, y) -> (f x, g y)

which go well with uncurry.

that’s all for now, but i will return to this topic another time.

fractals on the gpu (glsl)

February 7, 2010

there don’t seem to be a lot of decent shader examples floating around on the interwebs. there are some for the shader code, but few for the c code to set it up.
mandelbrot
source code: http://paste.uni.cc/20519

so, here’s the basic idea:

  1. include and init glew
  2. make a vertex shader object and a fragment shader object (and optionally a geometry shader)
  3. get shader code into strings (char*)
  4. attach the strings to the shaders
  5. compile the shaders
  6. make a program object
  7. attach the shader objects to the program objects
  8. link the program
  9. delete/free things you’re done with (shaders, strings)
  10. tell opengl to use the program

for this example, the shader is going to draw the mandelbrot set. that’s the set {z| z = z*z + c does not diverge}, where z and c are complex numbers
the pixels correspond to ‘c’, and you can guess weather the point will diverge by iterating z=z*z+c some number of times, and seeing if |z| goes above 2.

i’ll assume you can figure out how to get shader code into a string, but if not, take a look at the source code (at the bottom).
these create your shader and program objects:

GLuint glCreateShader(GLuint type), where type is GL_VERTEX_SHADER, GL_FRAGMENT_SHADER, or GL_GEOMETRY_SHADER
GLuint glCreateProgram()

attach code to shaders:
if your strings are nul terminated, lengths can be NULL.

void glShaderSource(GLuint shader, int number_of_strings,  char** strings,  int* string lengths)

attach shaders to program:

void glAttachShader(GLuint program, GLuint shader)

compile/link:

void glCompileShader(GLuint shader)
void glLinkProgram(GLuint program)

get compile/link errors:
these copy up to max_length of the log into the output string, and nul terminate it.

void glGetShaderInfoLog(GLuint shader, int max_length, int* chars_read, char* output)
void glGetProgramInfoLog(GLuint program, int max_length, int* chars_read, char* output)

use a linked program:

void glUseProgram(GLuint program)

now, onto the shaders:
for the vertex shader, we need a centre position, and a zoom level as inputs, and a complex number as ouput.

uniform vec2 pos;
uniform float zoom;
out vec2 c;

the calculation is pretty simple: use the standard matrix transform on the vertices, and use the raw vertex inputs to get the complex number:

void main() {
  gl_Position = ftransform();
  c = pos + gl_Vertex.xy * zoom;
}

the fragment shader has a bit more meat in it. it needs to get the complex number from the vertex shader, and the number of iterations from the opengl program.

in vec2 c;
uniform int depth;

and it needs a function to multiply complex numbers. (a+ib)(c+id) = ac-bd + i((a+b)(c+d) – ac – bd)

vec2 c_mult(vec2 a, vec2 b) {
  return vec2(a.x * b.x - a.y * b.y,
              (a.x+a.y)*(b.x+b.y) - a.x*b.x - a.y*b.y);
}

and a function to get the number of iterations before the mandelbrot thing diverges (between 0 and 1)
if |z| is above 2, the series diverges, so you can check for dot(z, z) > 4, to save a sqrt operation.

float mandel(int depth, vec2 c) {
  int i = depth;
  vec2 z = vec2(0.0, 0.0);
  while(i --> 0) {
    if(dot(z, z) < 4.0) {
      z = c_mult(z, z) + c;
    }
    else break;
  }
  return 1.0 - float(i)/float(depth);
}

and the main function needs to set the colour based on the result. i have it just multiplying purple, but you could sue a fancier function

void main() {
  gl_FragColor = mandel(depth, c) * vec4(1.0, 0.0, 1.0, 1.0);
}

in the opengl code, you’re going to need to pass pos, zoom, and depth to the shaders.
you need:

GLuint glGetUniformLocation(GLuint program, char* field_name)
void glUniform1f(GLuint location, GLfloat value)
void glUniform1i(GLuint location, GLint value)
void glUniform2fv(GLuint location, int array_length, GLfloat* values)

array_length should be 1. if your uniform variable is an array, it can be higher.

and that’s it. you just draw a rectangle or something, and it will have the set drawn on it.