clam has quit [Read error: 60 (Operation timed out)]
hdaume has quit []
async has quit [Remote closed the connection]
async has joined #ocaml
Smerdyakov has quit [Read error: 110 (Connection timed out)]
systems has joined #ocaml
Smerdyakov has joined #ocaml
systems has quit ["Client Exiting"]
mattam_ has quit [Read error: 110 (Connection timed out)]
mattam has joined #ocaml
Smerdyakov has quit [Read error: 104 (Connection reset by peer)]
Smerdyakov has joined #ocaml
det has joined #ocaml
polin8 has quit [Read error: 110 (Connection timed out)]
det has quit ["kapow"]
srv has joined #ocaml
srv has quit [Remote closed the connection]
rox has quit [orwell.freenode.net irc.freenode.net]
rox has joined #ocaml
pattern_ has quit [orwell.freenode.net irc.freenode.net]
pattern_ has joined #ocaml
buggs|afk has quit [orwell.freenode.net irc.freenode.net]
buggs|afk has joined #ocaml
Kinners has joined #ocaml
irchive_5 has quit [orwell.freenode.net irc.freenode.net]
Smerdyakov has quit [orwell.freenode.net irc.freenode.net]
Smerdyakov has joined #ocaml
irchive_5 has joined #ocaml
Smerdyakov has quit [orwell.freenode.net irc.freenode.net]
Smerdyakov has joined #ocaml
irchive_5 has quit [orwell.freenode.net irc.freenode.net]
brwill is now known as brwill_zzz
irchive_5 has joined #ocaml
Kinners has left #ocaml []
bk_ has joined #ocaml
polin8 has joined #ocaml
bk_ has quit ["I'll be back"]
bk_ has joined #ocaml
bk_ has quit ["I'll be back"]
bk_ has joined #ocaml
bk_ has quit [orwell.freenode.net irc.freenode.net]
pattern_ has quit [orwell.freenode.net irc.freenode.net]
Maddas has quit [orwell.freenode.net irc.freenode.net]
whee has quit [orwell.freenode.net irc.freenode.net]
themus_ has quit [orwell.freenode.net irc.freenode.net]
wax has quit [orwell.freenode.net irc.freenode.net]
brwill_zzz has quit [orwell.freenode.net irc.freenode.net]
asqui has quit [orwell.freenode.net irc.freenode.net]
bk_ has joined #ocaml
pattern_ has joined #ocaml
whee has joined #ocaml
asqui has joined #ocaml
themus_ has joined #ocaml
brwill_zzz has joined #ocaml
Maddas has joined #ocaml
wax has joined #ocaml
rox has quit [orwell.freenode.net irc.freenode.net]
rox has joined #ocaml
Maddas has quit [orwell.freenode.net irc.freenode.net]
whee has quit [orwell.freenode.net irc.freenode.net]
pattern_ has quit [orwell.freenode.net irc.freenode.net]
bk_ has quit [orwell.freenode.net irc.freenode.net]
themus_ has quit [orwell.freenode.net irc.freenode.net]
brwill_zzz has quit [orwell.freenode.net irc.freenode.net]
asqui has quit [orwell.freenode.net irc.freenode.net]
wax has quit [orwell.freenode.net irc.freenode.net]
irchive_5 has quit [orwell.freenode.net irc.freenode.net]
cm has quit [orwell.freenode.net irc.freenode.net]
skylan has quit [orwell.freenode.net irc.freenode.net]
polin8 has quit [orwell.freenode.net irc.freenode.net]
mr_bubbs_ has quit [orwell.freenode.net irc.freenode.net]
foxster has quit [orwell.freenode.net irc.freenode.net]
buggs|afk has quit [orwell.freenode.net irc.freenode.net]
mattam has quit [orwell.freenode.net irc.freenode.net]
teratorn has quit [orwell.freenode.net irc.freenode.net]
rox has quit [orwell.freenode.net irc.freenode.net]
Smerdyakov has quit [orwell.freenode.net irc.freenode.net]
mrvn has quit [orwell.freenode.net irc.freenode.net]
lam has quit [orwell.freenode.net irc.freenode.net]
clog has joined #ocaml
bk_ has joined #ocaml
mrvn has joined #ocaml
wax has quit [leguin.freenode.net irc.freenode.net]
buggs|afk has quit [leguin.freenode.net irc.freenode.net]
mrvn has quit [leguin.freenode.net irc.freenode.net]
bk_ has quit [leguin.freenode.net irc.freenode.net]
cm has quit [leguin.freenode.net irc.freenode.net]
mr_bubbs has quit [leguin.freenode.net irc.freenode.net]
irchive_5 has quit [leguin.freenode.net irc.freenode.net]
themus_ has quit [leguin.freenode.net irc.freenode.net]
pattern_ has quit [leguin.freenode.net irc.freenode.net]
rox has quit [leguin.freenode.net irc.freenode.net]
teratorn has quit [leguin.freenode.net irc.freenode.net]
Smerdyakov has quit [leguin.freenode.net irc.freenode.net]
asqui has quit [leguin.freenode.net irc.freenode.net]
clog has joined #ocaml
mrvn has joined #ocaml
bk_ has joined #ocaml
whee has joined #ocaml
bk_ has quit [Client Quit]
polin8 has joined #ocaml
Maddas has joined #ocaml
mattam has joined #ocaml
brwill_zzz has joined #ocaml
pnou has joined #ocaml
async has joined #ocaml
lam has joined #ocaml
srv has joined #ocaml
bk_ has joined #ocaml
foxster has joined #ocaml
mrvn_ has joined #ocaml
mrvn has quit [Read error: 110 (Connection timed out)]
mrvn_ is now known as mrvn
thomas_ has joined #ocaml
<thomas_>
hi,i'm pretty new to ocaml and wrote a small and very simple tetris like game in a purely functional style just for fun. will this be slower as a iterative version?
<thomas_>
(the sdl graphic output has iterative elements,but i think this is unavoidable)
<Maddas>
cool!
<Maddas>
thomas_: it's probably more a matter of how much time you spend optimizing it
<Maddas>
doesn't it run smoothly?
<thomas_>
very simple = only draw filled boxes
<thomas_>
i thin the game is that simple it can't run not smoothly
<thomas_>
it's only about 200 lines of code and far away from beeing finished yet
<Maddas>
:)
<thomas_>
but it is my first functional programm
<mrvn>
Hardest part will be drawing. The Graphics module redraws the complete frame every time.
Riastradh has joined #ocaml
<thomas_>
mrvn: i use ocamlsdl
<thomas_>
but i think redraw the whole frame is usual in games
<thomas_>
every 3d game has to
<mrvn>
tetris only has to move some blocks.
<thomas_>
yes but a game that simple won't suffer from redrawing all blocks i think
<mrvn>
with the usual stepping of blcoks as they fall down not. smooth falling might stress some older cpus.
<thomas_>
i more think the problem with functional programming is that you are unable to modify a data structure,but have to recreate a new one (with modified data). or i got functional programming wrong
<Riastradh>
thomas_, that's why OCaml provides you with mutable record field.
<thomas_>
Riastradh: but i wanted to stay with functional programming.
<mrvn>
and with arrays
<Riastradh>
thomas_, what's wrong with writing mostly functional code, with imperative bits very well-fenced-off and easy to distinguish from the rest?
<thomas_>
Riastradh: nothing i think,it's more a restriction i set in my mind because i did iterative programming for many years
__buggs has joined #ocaml
buggs|afk has quit [Read error: 60 (Operation timed out)]
brwill_zzz is now known as brwill
lophty_ has joined #ocaml
Riastrad1 has joined #ocaml
Riastradh has quit [Nick collision from services.]
Riastrad1 is now known as Riastradh
Vincenz has joined #ocaml
Smerdyakov has quit [Read error: 110 (Connection timed out)]
Smerdyakov has joined #ocaml
<thomas_>
hmm what are advantages of OCaml over SML except for the OOP interace?
<whee>
does SML have any sort of preprocessor?
<Maddas>
*ML aren't LISP dialects, are they?
<Maddas>
(Strictly speaking)
<whee>
no
<Maddas>
Good :-)
<whee>
pfft, lisp is fun :P
* thomas_
misses thread support in lisp
<mrvn>
What for? lisp has callc, right?
<whee>
mrvn: I don't think it's in common lisp
<whee>
of course it's in scheme, though
<mrvn>
callc, instant thread support.
* Vincenz
likes scheme better than lisp
<Vincenz>
plt-scheme..
<whee>
some common lisp implementation include threading libraries, still
<Vincenz>
plt-scheme comes with a REALLY nice library
<whee>
Vincenz: I like lisp more, but that's just because I could never find a scheme implementation I liked
<whee>
plus, I'm still not sold on hygenic macros
<Vincenz>
whee: try plt
<Vincenz>
whee: what's the advantage of non-hygienic?
<Vincenz>
have an example?
systems has joined #ocaml
<whee>
I just think it's an unnecessary restriction
<systems>
which restriction is this
<Vincenz>
whee: for that matter I could say english is better than lisp cause it has less restrictions, some restrictions aren't really restrictions
<systems>
what restriction
<whee>
I suppose
<whee>
I just don't see them as solving an actual problem
<systems>
wut restriction :(
<whee>
systems: hygenic macros automatically prevent you from capturing bindings when the macro is expanded
<Maddas>
whee: oh, lisp certainly is ufn
<Maddas>
fun
<whee>
in lisp you'd have to gensym your symbols unless you wanted to use an existing bind name
<Maddas>
I said 'good' because that's what I said in an argument (ML isn't a LISP dialect) :)
<whee>
I just think it'd be good to have the option of capturing bindings when you'd like
<Vincenz>
what's capturing bindings?
<whee>
well, variables in the lisp sense :P
<Vincenz>
yeah I figured, but what does it mean to capture a variable in a macro/
<whee>
if you had a macro that dealt with a variable named "foo", and it was expanded in a context that had a variable named "foo", the macro would operate on the foo in that context
<whee>
so instead of naming the variables inside your macros, you use lisp's gensym to get a unique one for that expansion
<Vincenz>
dangerous
<whee>
perhaps, but can also be useful
<Vincenz>
hmm, I'm not trying to criticize, but could you show me an example?
<whee>
just because it can be dangerous doesn't mean the programmer should be restricted
<whee>
not off the top of my head, heh
<Vincenz>
I know, but I'm trying to figure out (aka learn, not bash) ...
<whee>
yes, I know :)
<whee>
oh, okay
<Vincenz>
?
<whee>
with hygenic macros you can't create bindings that other code fragments can use, I believe
<Vincenz>
hmm
<Vincenz>
how often do you use them?
<whee>
so you could create a macro that expanded to something, and created some binding (common example is anaphoric if, which creates an "it" binding referring to the condition)
<Vincenz>
you can create an anaphoric if in scheme iirc
<whee>
it's useful when chaining things together if you can refer to the last computation as "it" or some other name
<whee>
I don't think you can
<whee>
when you create a binding in a scheme macro you get one specific to that macro
<Maddas>
do you guys use any Scheme / Lisp for "proper" stuff?
<whee>
Vincenz: look at the definition of aif there
<Maddas>
e.g. as a C replacement :)
<whee>
it's about 60% of the way down
<Vincenz>
thnx
<whee>
I hope that's not the only way to implement that in scheme :)
<whee>
it's a three liner in common lisp, heh
<Vincenz>
I suck at macros....
<Vincenz>
:(
<whee>
the problem I have with hygenic macros being the default is you have to really go out of your way to capture a binding
<Vincenz>
so you've used it for a problem
<whee>
and the work to do that is a lot more than simply assuming you're going to capture everything and gensyming when you don't want to
<Vincenz>
hmm
<whee>
I've used anaphoric macros a lot, they do save time and make things clearer
<Maddas>
do you guys use any Scheme / Lisp for "proper" stuff?
<Maddas>
:)
<Vincenz>
what's an anaphric if exactly?
<Vincenz>
Maddas: I did the competition
<Vincenz>
Maddas: I don't have much of a choice, I'm stuck to the language the company I currently have a project at uses
<Maddas>
ok :)
<whee>
Vincenz: it binds the result of the condition to a variable
<Vincenz>
ahhhhh
<Vincenz>
hmm....
<Maddas>
what kind of a project is done with Scheme?
<Maddas>
Just wondering :)
<Vincenz>
(if (something) #t #f)...
<Vincenz>
whee: how's that differnet?
<Vincenz>
or just...
<Vincenz>
(something)
<whee>
well, you could do something like (aif (some-query blah) (do-something-with it))
<whee>
because the "it" variable would be the result of that query
<Vincenz>
ohhhhhhhhhhhh
<Vincenz>
(let ((a some-quary....)) ( if (a) (do something a))
<Vincenz>
?
<whee>
yes, basically
<Riastradh>
whee, hygienic macros also solve a different problem.
<Riastradh>
Suppose you have a SWAP! macro.
<Riastradh>
(swap! x y) should set X to Y's previous value and vice versa.
<Riastradh>
A very naive implementation might be:
<Riastradh>
(defmacro swap! (x y)
<Riastradh>
(let ((val ,x))
<Riastradh>
(set! ,x ,y)
<Riastradh>
(set! ,y val)))
<Riastradh>
The first problem is obvious.
<Vincenz>
val
<Riastradh>
What if you do (swap! x val) or (swap! val x)? A naive CLer would rewrite it as:
<thomas_>
x and y are evaluated twice
<Riastradh>
(defmacro swap! (x y)
<Riastradh>
Oops, er.
<mrvn>
Did I stray to #lisp?
<Riastradh>
The first macro should have had a ` before the (let ...).
<Riastradh>
Anyhow, a naive CLer would rewrite it as:
<Riastradh>
(defmacro swap! (x y)
<Riastradh>
(let ((val (gensym 'val)))
<Riastradh>
`(let ((,val ,x))
<Riastradh>
(set! ,x ,y)
<Riastradh>
(set! ,y ,val))))
<Riastradh>
But this has another problem.
<Riastradh>
You wouldn't want someone to do (let ((set! +)) (swap! a b)); you want to use the SET! that rebinds variables, no matter what someone shadows it as.
<Riastradh>
If we wrote this with syntax-rules, which is automatically hygienic:
* bk_
ignores all of this, concentrates on learning ocaml
<Riastradh>
(define-syntax swap!
<Riastradh>
(syntax-rules ()
<Riastradh>
((_ ?x ?y)
<Maddas>
mrvn: seems like pretty much everybody in #ocaml knows LISP or Scheme
<mrvn>
We moved on, do we still need to talk about it? :)
<whee>
that is a pretty valid reason for them, heh
<Riastradh>
Then both problems would be solve: VAL would not be unhygienically captured _and_ the right LET and SET! would be used.
<Vincenz>
bk_ does have a point
<Riastradh>
Without using complicated trickery with package cruft, you can't do this right with unhygienic-only macros and GENSYM.
<Riastradh>
OK, sorry for the Lisp code in #ocaml, but I'm done now.
<thomas_>
let swap a b = let t=!a in a:=b;b:=t ?
<thomas_>
lisp misses references imo
<Riastradh>
thomas_, in OCaml it's entirely different, because while Lisp has mutable variables, OCaml has immutable variables and mutable references.
<thomas_>
is it possible to write a function swap in lisp?
<Riastradh>
References and mutable variables are entirely different.
<Riastradh>
thomas_, depends on what Lisp you're talking about.
<thomas_>
ansi common lisp
* mrvn
still wonders that there is so little support for common protocols and formats in ocaml.
<mrvn>
And what is there is incomplete or sucks.
<whee>
I always used psetq or psetf to do a swap in CL
<Riastradh>
I'm not really familiar with what CL has in terms of environment manipulation, but if you can grab the current environment and modify it, then yes, you could write a SWAP! in CL.
<Riastradh>
But the exact example is irrelevant.
<Riastradh>
My point still stands about the right LET and SET! being used.
<Riastradh>
SWAP! just happens to be a very simple example that can have both problems in it.
<Riastradh>
s/you could write a SWAP! in CL/you could write a SWAP! function in CL/1
<Vincenz>
you can write a swap! function in assembler too
<Maddas>
hmm
<Maddas>
who won? :)
<teratorn>
mrvn: like what?
<teratorn>
Maddas: me!
<Riastradh>
Maddas, ?
<Vincenz>
mrvn: yeah it's a shame that there's no big standard lib for ocaml
<Vincenz>
every time you want something you have to download the c-source and compile it into a lib
<mrvn>
teratorn: currently a mirror script for debian.
<Riastradh>
mrvn, what's stopping you from writing them?
<mrvn>
time
<Vincenz>
Riastradh: a good language has more than a very handy syntax, you can't reinvent the wheel for every project
<Riastradh>
Vincenz, yes, and...?
<Vincenz>
it's a pity there's no richer lib for ocaml?
<thomas_>
which language comes with all this?
<Riastradh>
Write the libraries!
<mrvn>
python, c, c++
<mrvn>
perl
<Vincenz>
scheme
<Vincenz>
java
<thomas_>
mrvn: C++ comes with ftp support?
<Riastradh>
In Python, which has a _very_ large number of libraries and a very large community, _someone_ had to write a bunch of libraries first.
<mrvn>
thomas_: there are many libs for it.
<mrvn>
all the C libs too
<thomas_>
mrvn: so there should be one for OCaml...write one ;-)
<Vincenz>
Riastradh: true, but not everyone has the time for that
<mrvn>
thomas_: I am, but it sucks.
<Riastradh>
Most arguments I've heard for using Python is that there are a lot of libraries and there is a big community for it. The libraries didn't come out of nowhere; Python didn't start out like that. A small number of initial people had to write lots of initial libraries.
<Maddas>
Same with Perl
<bk_>
perl, yuk
<bk_>
sorry
<teratorn>
:)
<Maddas>
Stop it
<Maddas>
:)
<bk_>
:p
<systems>
ocaml is a secret elites weapon
* Vincenz
grins
<Maddas>
haha
<Maddas>
:-)
<thomas_>
btw:does the ocaml compiler make use of MMX/SSE/... ?
Xcalibor has joined #ocaml
<Vincenz>
thomas_: euhm...
<Vincenz>
thomas_: the compiler compiles to bytecode
<Vincenz>
if you want native, you have to have a c compiler
<Xcalibor>
hello :)
<bk_>
hello xcalibor
<Xcalibor>
what's up?
<thomas_>
Vincenz: ocamlopt ?
<Vincenz>
hmm
<Vincenz>
yes, I think you need a compiler for it
<Vincenz>
(c ...)
<Vincenz>
or wait...maybe just an assembler
<Vincenz>
I'm not sure
<thomas_>
gcc also needs a assembler
<Vincenz>
true, but if it only needs an assembler then ocaml should take care of mmx
<Vincenz>
otherwise it's gcc that doesit
<whee>
Vincenz: you just need an assembler and a linker for ocamlopt to work
<Vincenz>
oh
<Vincenz>
then I was wrong
<thomas_>
so ocaml would have to do mmx
<Vincenz>
then I don't know if ocaml supporst mmx
<whee>
that's typically gcc and ld for the free unices
<thomas_>
gcc as assembler?
<thomas_>
AS - the portable GNU assembler. <-- ?
<Vincenz>
I wish more people would use nasm
<thomas_>
because of the syntax?
<Vincenz>
yes
<whee>
thomas_: gcc accepts assembly
<whee>
it might just go call as, I'm not sure
<thomas_>
yes but why rely on gcc?
<Xcalibor>
the gnu assembler is gas, of course :)
systems has quit ["Client Exiting"]
<Xcalibor>
nasm is okay, but I guess it's less portable than gas
<Xcalibor>
and GCC goal is portability...
<whee>
thomas: it doesn't
<whee>
it'll use the assembler and linker that the platform provides
<whee>
in windows you can use msvc for that, if you'd like
* Vincenz
uses msvc
<Xcalibor>
btw, is there a way to see what a library.so oftfers in terms of functions?
<Vincenz>
but that does leave the question
<Vincenz>
does ocaml support mmx?
<thomas_>
whee: does ocamlopt generate mmx instructions?
<whee>
I don't think it uses it for anything
<Xcalibor>
Vincenz: mmx shoul dbe supported by the graphics library, or the multimedia libraries in any case, don't you think?
<Vincenz>
Xcalibor: euhm...that has nothing to do with ocaml, but rather with how the graphics lib was compiled
<Xcalibor>
Vincenz: just what I say... OCaml will support MMX as far as it's multimedia libraries provide MMX instructions on Intel chips
<Vincenz>
true
<Vincenz>
but I'm curious if the code you write in ocaml gets compiled to mmx when it's needed
<Xcalibor>
you mean normal code? like the factorial function?
<thomas_>
i think we mean that ocamlopt will try to generate MMX instructions for everything it compiles
<Xcalibor>
but MMX is just for multimedia stuff, right?
<Vincenz>
Xcalibor: mmx is for anything that can use SIMD
<Vincenz>
anything that's mathematically parallel
<thomas_>
Xcalibor: mmx is more extra cpu instructions
<Vincenz>
Xcalibor: it just turns out that for multimedia you have a lot of data that's being processed the same way
<Xcalibor>
mmm... I see...
<Vincenz>
for example
<Vincenz>
...
<Vincenz>
consider adding 2 numbers of 16 bits
<Xcalibor>
so the question could be if it also emits 3DNow! AMD instructions...
<thomas_>
yes Xcalibor
<Xcalibor>
2 numbers of 16 bits? on a Pentium?
<Vincenz>
fine
<Vincenz>
32 bits
<Vincenz>
...
<Vincenz>
add them
<Vincenz>
now let's say you want to add 4 pairs of numbers
<Xcalibor>
okay, 1 instrcution
<Vincenz>
...wait
<Xcalibor>
i wait
<Vincenz>
let's keep going with 16 bits
<Vincenz>
if you wanted to add 2 pairs of 16 bits
<Vincenz>
you cant' stick them in a 32 bits because of carry...
<Vincenz>
with mmx
<Vincenz>
you can stick them in a 32 bit register (or in the case of mmx 64 or 128, can't remember)
<Vincenz>
and you can choose to turn off carry every 8, 16, or 32 bits
<Vincenz>
and thus add 2 pairs of numbers in parallel
<Vincenz>
same for multiplication,etc...
<Vincenz>
that's the basic idea
<Vincenz>
plus you have support for really big numbers (in case you don't turn the carry off)
<Xcalibor>
Vincenz: i see... not exactly multimedia instructions...
<Vincenz>
they're called that way cause of marketing
<Vincenz>
technically it's SIMD
<Vincenz>
single instruction, multiple data
<Vincenz>
multimedia just happens to have a lot of raw data that needs to be processed
<Vincenz>
and usually you want to do the same thing to every pixel, sample, what not
<Xcalibor>
indeed...
<Xcalibor>
well, considering ints are 31 bits, i don't think they fit the mmx model very well...
<Vincenz>
euhm...
<Vincenz>
ints are 32 bits
<Vincenz>
the first bit is a sign bit, if the data is signed
<Vincenz>
in multimedia the data is usually not signed
<Xcalibor>
in Ocaml they are 31 (63)
<Vincenz>
cause they're signed
<Vincenz>
no?
<Xcalibor>
nopwe... it it's on its boxed type. if not it's an int
<Vincenz>
hmm
<Vincenz>
oh
<Vincenz>
didn't know that
<Xcalibor>
OCaml uses one of the bits in an int internally to differentiate between integers and pointers. This is why the basic int is 31 bits, not 32 bits (63 bits if you're using a 64 bit platform).
<Vincenz>
ah
<Vincenz>
interesting
<Xcalibor>
yup
<Vincenz>
so what if your pointer...(32 bits) points in the first half of memory?
<Vincenz>
then the first bit is 0...
<thomas_>
so pointers are also only 31 bit?
<Vincenz>
so it would be an int?
<Vincenz>
what thomas_ asked
<thomas_>
that's weird
<Xcalibor>
a pointer is actually amutable variable
<Xcalibor>
in OCaml, variables are aliases
<Xcalibor>
the first bit differentiates between an integer value and a memory position
<Vincenz>
but then you only have 31 bits of memory space
<Vincenz>
not 32
<Vincenz>
how does that match up with reality?
<Xcalibor>
this is the type system:
<Xcalibor>
OCaml type Range
<Xcalibor>
int 31-bit signed int, roughly +/- 1 billion
<Xcalibor>
float IEEE double-precision floating point, equivalent to C's double
<Xcalibor>
bool A boolean, written either true or false
<Xcalibor>
char An 8-bit character
<Xcalibor>
string A string
<Xcalibor>
unit Written as ()
<thomas_>
Xcalibor: sorry you don't get what we mean
<Vincenz>
yes but pointers are only 31 bits, all variables are pointers (cause they're all references)....
<Vincenz>
and normally in pc's pointers are 32 bit
<Vincenz>
and memory in a computer is not contiguous (iirc), so you might have some memory that needs the first bit set in the pointer to access it
<Xcalibor>
well, it depend on the type of pointer
<thomas_>
Xcalibor: the ocaml implemention stores pointer (c-style-pointer) only as 31bit values?
<Vincenz>
thomas_: I bet once it gets compiled natively it uses 32 bits, I bet it only uses 31 bits when running in bytecode
<Xcalibor>
dunno
<Xcalibor>
because refs are not pointers
<Xcalibor>
they are just so like them
<thomas_>
Vincenz: and the 31bits don't refer to system memory but to some ocaml spezific location?
<Vincenz>
thomas_: most likely, no?
<thomas_>
so the max memory a ocaml program can use is 2G?
<Vincenz>
thomas_: you can't access system stuff directly anyways, right? you need libs for that (written in c)
<mrvn>
pointers are usually aligned and in ocamls case 4 byte aligned.
<Vincenz>
thomas_: the max a normal program can use is 4G, I think that it's not much different
<Vincenz>
hehe, imagine 10 years ago
<Vincenz>
2 G....why...that's INFINITY, why would you EVER need 32 bits? come on...16 bits is MORE than enough
<Vincenz>
now you could probably get a desktop pc with 1-2 g
<Xcalibor>
this is how OCaml stores a string:
<Xcalibor>
4 byte header the string padding
<Xcalibor>
4348 h e l l o , w o r l d \n \0 \0 \002
<mrvn>
Vincenz: I have several progs that use 6-30G easily.
<Vincenz>
mrvn: 64 bit processor?
<mrvn>
sure.
<Vincenz>
mrvn: cool by the way, what progs?
<mrvn>
dna analysis
<Vincenz>
neat
<Vincenz>
phd/
<Vincenz>
?
<mrvn>
no. student
<Vincenz>
in what lang?
<mrvn>
c, c++, ocaml
<Vincenz>
And what do you study?
<mrvn>
computer science.
<Xcalibor>
mrvn: I once tweaked/modified one that run on a hugely, severily, parallelized, vectorial machine... a single run was easily 5 hours of real CPU time with more than 256 Gb RAM (shared in 4 queues, but anyway...)
<Vincenz>
what do you do with the dna?
<mrvn>
looking for possible structures.
<Vincenz>
I can't wait until 64bits break out in desktops
<mrvn>
The algorithm I designed is a real big memory waster-
<Xcalibor>
lol: they have, it's called PowerPC :)
<Vincenz>
I mean...intel/amd based
<mrvn>
and amd64
<mrvn>
and ia64
<Vincenz>
yeah but they're not standard yet...software is still 32 bit
<mrvn>
and alpha, s390x, sparc64
<mrvn>
Vincenz: yours maybe.
<Vincenz>
...
<mrvn>
What I realy hate is that ocaml only has 24 bit for arrays.
<Xcalibor>
mrvn: ours was a functional of a Cobalt 13 cluster with all interactions between electrons and nuclei, looking for the ground state on a sigma-3 symmetry... very slowly converging cluster
<Vincenz>
I know ti exists, I said "break out"
<Vincenz>
either way, what does your prog do with the dna?
<Xcalibor>
Vincenz: I mean, you can buy a G4 and install a Debian on it, et voilá
<Vincenz>
true
<Vincenz>
but seeing I use windows..
<mrvn>
Vincenz: just looks for certain structures.
<Xcalibor>
windows? oh, so you are studying worm dna? ;-)
<Vincenz>
I don't study dna
<Maddas>
haha
<mrvn>
Vincenz: I'm just designing the prog to search. I'm not interpreting the results.
<Xcalibor>
i mean, windows is full of worms and viruses.... :)
<Vincenz>
mrvn: small tip, though you most likely know this, fix your memory stuff, memory is what usually cripples an application
<Vincenz>
...
<Vincenz>
Xcalibor that's great
<Vincenz>
Xcalibor I have linux too, I just find windows fine for my current needs
<Xcalibor>
lots of things to study there...
<Xcalibor>
Vincenz: but you are stuck to 32bits
<Vincenz>
yes and most software running in most companies is too
<Vincenz>
it's great to be idealistic and say "wow linux, wow ocaml, wow ..."
<Vincenz>
and I say that too
<Maddas>
huh?
<mrvn>
Vincenz: Doesn't matter. I'm doing theoretical stuff. I garanty a certain runtime and memory usage in my algorithm and for that it needs to waste lots of ram.
<Vincenz>
but on the other hand you als have to look at the real world and be a realist
<Maddas>
you think not using windows is idealistic?
<Maddas>
haha
<Vincenz>
Maddas: yes I know linux is better than windows
<Xcalibor>
Vincenz: bullshit, most companies run on Solaris, AIX, HP/UX
<Vincenz>
...
<Riastradh>
I never use Windows, and I'm not much of an idealist!
<Vincenz>
you dind't get my point
<whee>
windows is for games, the bsds are for work :)
<mrvn>
Vincenz: It eats up lots of ram but it won't get stuck for ours on some random hard case.
<Maddas>
whee: I completely agree
<Vincenz>
mrvn: ah I see
<Xcalibor>
whee: same here
<Maddas>
Vincenz: no, I'm talking about enterprise usage
<whee>
linux is just for laughing at when they rewrite the vm and/or scheduler and slap a stable vesrion number on it
<Maddas>
indeed
<Maddas>
but then, for home use it doesn't matter much
<mrvn>
Vincenz: I use O(n^(4k+4)m) ram and time with n being the length of the dna and k a factor from the structure thats searched (usually small, say 3-6).
<Vincenz>
Maddas so am I, and all software I've developed so far has been under windows, as for my own usage. All the things that I need from linux I have in windows, some things, mostly look and feel that I need from windows I don't quite have in linux, personally .... I know linux is better, but for my personal needs windows is better.
<Maddas>
(I don't like Linux, I only use *BSD and occasionally Windows for gaming, but oh well)
<Xcalibor>
well, some linux kernels are just okay.... they simply get out more versions than the bsds gangs
<Maddas>
Vincenz: you say 'for your own usage', but yet you judge about the 'real world' only using Windows?
<Vincenz>
Maddas: all the projects I've worked on were on windows
<mrvn>
Vincenz: mus suck
<mrvn>
must even
* Vincenz
shrugs
<Maddas>
most
<Maddas>
hm
<Vincenz>
I have VIM
<Riastradh>
Vincenz, better projects wouldn't have depended on the platform.
<Vincenz>
I have grep, I wrote my own version of cat
<mrvn>
Only 4G of ram, how limiting. :)
* bk_
has only worked on solaris for $$$
<Vincenz>
Riastradh: actually we cross compile for tandem in the current project
<Maddas>
Vincenz: grep, cat and vim are hardly the main differences between UNIX and Windows :)
<Vincenz>
Maddas: it's what I need from linux
<Vincenz>
well maybe bash for completion :P
<Maddas>
Well, good for you then.
<Vincenz>
yes and good for you use linux:)
<Maddas>
I found working in Windows a terrible pain
<Maddas>
I don't use linux
<Vincenz>
so don't bash me next time I say I use windows
<Vincenz>
or bsd
<Maddas>
I never did
* Riastradh
bashes Vincenz.
<Vincenz>
or mac
<Vincenz>
it's a personal preference thing
<Maddas>
I love OS X
<Maddas>
I never bashed you for using anything, Vincenz
<Vincenz>
so why are we having this conversation, and it wasn't necessarily only intended at you
<Maddas>
because you said that the "real world" sticks to Windows
<Maddas>
:)
<Vincenz>
mine does :P
<Vincenz>
the only linux used at the company where I work is for all the webservers and the alpha servers, but they're sort of there
<Vincenz>
the main software runs on tandem (faulttolerant system), and the development for taht uses MS.Net with a cross compiler from compaq plugged into it
<mr_bubbs>
CP/M is the best
<Maddas>
don't judge the whole world by personal experience, else I would have to say that every professional company uses Perl, nothing else.
<Vincenz>
last company was for multimedia presentation and it was also on windows
<Maddas>
so, that's three or four companies. Of how many that exist? :)
<Vincenz>
hmm, alright, touche
<Vincenz>
I'm just tired from the "usual" crap I get when I say I use windows...sorry
<Vincenz>
I guess I unloaded unto you
<Maddas>
:)
<Vincenz>
I know windows isn't perfect, heck I criticize it myself, I just find it more accustomed to my needs
<Vincenz>
anyways, back to 31 bit pointers
<mrvn>
30 bit.
<mrvn>
and shifted 2 bits.
* Vincenz
wonders what it owuld have been like to have a commodore and a 128mb usb stick with interface
<mrvn>
Vincenz: C64 only supports 16 MB ram afaik.
<Vincenz>
he, I only had 64k
<mrvn>
there is special hardware to support banks
<Vincenz>
ah
<mrvn>
Like the 64G extension on intel.
<Vincenz>
mrvn: so basically...if it's shifted 2 bits...it's 4-byte aligned (is that word or dword, I always forget)
<Vincenz>
?
<mrvn>
Vincenz: depends on the cpu
<Vincenz>
hmm, so what happens to strings?
<mrvn>
Vincenz: 4 byte aligned
<Vincenz>
but...4 chars right?
<Maddas>
Heh. What do Banks usually use to code? :)
<Vincenz>
or 1 char every 4 bytes?
<mrvn>
4 byte tag+size (24 bit size) and then array of bytes+padding
<Vincenz>
oh
<mrvn>
list of char is 8 (or 16 on 64bit) byte per char.
* Vincenz
nods
<Vincenz>
it's just that the starting address is 4 byte-aligne
<Vincenz>
right?
<mrvn>
yep.
<Vincenz>
so what if you do...(in c syntax
<Vincenz>
*a = &b[1]
<mrvn>
And it starts with a special bitpattern saying I'm a string of size x.
<mrvn>
Vincenz: you can't in ocaml.
<Vincenz>
you have to copy the whole string to get the entire string minus the first char?
<Vincenz>
the idea is to get a string starting with the second character of the original string
<mrvn>
Thats what String.sub does.
<Xcalibor>
strings end in \002
<mrvn>
Since strings are mutable you have to copy them anyway.
<Vincenz>
oh
* Vincenz
nods
<Vincenz>
true
<mrvn>
With lists you can share the tail since nothing can change it.
<mrvn>
(usually).
<Vincenz>
how are lists stored?
<Vincenz>
[data, pointer-to-next] ?
<mrvn>
header, item (or pointer to it) and next/nil
<mrvn>
Everything has a header.
<Vincenz>
wow
<Vincenz>
lots of memusage
<mrvn>
Except ints,l which are stroed in the header.
<Vincenz>
"unboxed" ?
<mrvn>
memory is allways boxed
<mrvn>
Otherwise the GC would get confused.
<thomas_>
hmm are there also unboxed floats?
<mrvn>
The compiler unboxes stuff in registers.
<Vincenz>
I heard there was a special case for float arrays or int array
<mrvn>
Vincenz: Big Arrays. One big box saying don#t touch me.
<Vincenz>
ah
<Xcalibor>
floats are boxed
<Vincenz>
bet the box has a windows logo on it (couldn't resist)
<Xcalibor>
they are IEEE floats
<mrvn>
I'm not sure elements in an array need to be boxed.
<mrvn>
But you need the box if someone references an element of an array.
<Xcalibor>
arrays: As a special hack to make this go faster, OCaml implements arrays of unboxed floats.
<mrvn>
But any language with a full GC needs boxing.
<mrvn>
Xcalibor: Are they copied when you do let f = a.[3] in?
<Vincenz>
cool site
* Vincenz
reads
<mrvn>
What I don't get is why ocaml has a 0 tag for pointers an a 1 tag for ints.
<mrvn>
slows down ints.
<Xcalibor>
You can find out more about how OCaml represents different types by reading chapter 18 of the manual ("Interfacing C with Objective Caml") and also looking at the mlvalues.h header file.
<Vincenz>
Xcalibor you mean 13?
<Vincenz>
mrvn: the size of strings is maximally 22 bits...not 24 bits...
<mrvn>
Arrays can be 16M big, thats 24 bit. But the lower 2 bits are probably left out.
<mrvn>
So arrays will be 22 bit but in words not bytes.
<mrvn>
32 bit cpus realy suck.
<Vincenz>
ouch.......
<Vincenz>
for ints...
<Vincenz>
the bit denoting it's an int
<Vincenz>
is the LSB
<Vincenz>
and it's 1
<Vincenz>
so 3 becomes 7 in assembly
<mrvn>
yep.
<Vincenz>
wouldn't it have been smarter to use the MSB
<Vincenz>
and have it = 0
<mrvn>
No, pointers have the lowest bit unused.
<Vincenz>
means every time you want to do something with them
<Vincenz>
you have to shift them first
<mrvn>
Having it 0 would have been smarted though since an offset on pointers is normaly free.
<mrvn>
Vincenz: why? 1+1=2 becomes 2+2=4
<mrvn>
shifting isn't a problem.
<Vincenz>
yes it is
<mrvn>
most of the time.
<Vincenz>
take 3 + #
<Vincenz>
take 3 + 3
<Vincenz>
in assembly....
<Vincenz>
7 + 7
<Vincenz>
7 +7 = 14
<Vincenz>
shift back you get 7
<mrvn>
Vincenz: Thats the tag bit
<Vincenz>
3 + 3 is 6
<Vincenz>
yeah
<Vincenz>
but if you want to add
<Vincenz>
you have to shift the numbers first..
<mrvn>
no
<Vincenz>
3 + 2
<mrvn>
due to the tag bit a+b beomes a+b-1
<Vincenz>
in asm
<Vincenz>
still an extra op
<mrvn>
But its not the shifting causing it.
<Vincenz>
plus...-1 is expensive...
<Vincenz>
shifting would be better
<Vincenz>
cause now you have to load the 1 (data) into the register
<Vincenz>
it's much faster to shift
<mrvn>
Vincenz: all cpus I know of have add/sub immediate.
<Vincenz>
you still have to load the 1 into the pipeline
<mrvn>
Vincenz: maybe only from -8 to +7 but without annother register.
<mrvn>
Vincenz: the 1 is in the opcode.
<Vincenz>
-1?
<mrvn>
Also if you do several operations on an int you unbox ist (-1) at the start and box it (+1) at the end.
<Vincenz>
hmm
<Vincenz>
true
<mrvn>
Vincenz: m68k has add/sub with values of -8 to 7. Alpha has -32768 to 32767. Intel somewhere inbetween
<Vincenz>
as a different instruction altogether?
<mrvn>
Vincenz: The ocaml compiler quite sucks on alpha though. It adds/removes the int tag all the time. Doesn't do unboxing.
<Vincenz>
instead of an extended instruction containing data
<Vincenz>
yick
<mrvn>
floats are worse, they are kep in memory all the time.
<mrvn>
Loading/storing a float takes ages.
<mrvn>
But thats all an implementation problem and not a designfault.
<mrvn>
And you are right, using 0 for ints and 1 for pointers would have been better.
<mrvn>
Is it slower to use -1(dx) on i386 instead of (dx)?
<mrvn>
in asm
<Vincenz>
now that I think of it tho...using 0 for pointers is not all taht bad
<Vincenz>
usually you're working with variables and functions
<Vincenz>
which are pointers
<Vincenz>
because pointers are word aligned the last 2 bits have to be 0
<Vincenz>
:)
<Vincenz>
anyways
<Vincenz>
night
brwill is now known as brwill|food
Vincenz has quit ["Sleep"]
<mrvn>
Vincenz: No, you can add 1 to all pointers and use them all with an offset -1 in the opcodes.
<thomas_>
btw:why does ocaml need this int/pointer stuff at all? types are known at compile time...
<mrvn>
and how do you free memory?
<thomas_>
hmm i mean for int the compiler knows its a integer and for structured values it knows its a pointer...or i got sth. wrong
<mrvn>
The GC doesn't.
<Maddas>
ah, just free the damn memory already! The computer wont notice a few bytes more or less! ;)
<mrvn>
The GC needs to know what is a pointer so it sees that where the pointer points too is still alive.
<mrvn>
You could store a bitmask in the header that says what words are pointers though. More complicated.
<mrvn>
And the header size would vary with the structure size.
<mrvn>
You also need the color bit for the GC to mark objects.
<Maddas>
8===D
<Maddas>
heh, sorry
<mrvn>
How does that work with arrays anyway? An array is alive as long as one member is alive. Does the GC look through the complete array every time till it finds a live one?
<thomas_>
btw: why GC at all? are cyclic references the only issue with reference counting?
<mrvn>
pretty much
<mrvn>
also defragmentation
<mrvn>
ocaml uses a moving garbage collector.
<mrvn>
Also uses seasoning so its very fast too.
<mrvn>
Imagine increasing/decreasing an int every time you copy something. Also every structure would need to have the counter and arrays get realy complicated.
<Smerdyakov>
mrvn, why is an array alive as long as one member is alive?
<mrvn>
Unless you want to free bits and pices at a time it is.
<mrvn>
ocaml probably frees it in pieces.
<mrvn>
But eigther way you have a problem with reference counting.
<Smerdyakov>
What does it mean for a member of an array to be alive?
<mrvn>
Someone has its adress (let a = b.[17] in)
<Smerdyakov>
When would someone have its address?
<Smerdyakov>
I don't think such a situation is possible in OCaml.
<mrvn>
allways.
<Smerdyakov>
In the code you gave, a has the _value_ stored in the cell, not any kind of reference to the cell itself.
<mrvn>
Smerdyakov: Only for ints, not for lists or records or classes.
<Smerdyakov>
So, for instance, an array of lists has enough space allocated to store a nil or cons cell inline for each element?
<mrvn>
I think so. Or is it an array of pointers to lists?
<mrvn>
must be pointers since arrays are mutable.
<Smerdyakov>
I would guess the latter.
<mrvn>
Otherwise a.[17] <- [] would change a list.
<Smerdyakov>
I think it is impossible to have a reference to an array cell.
<mrvn>
It must be an array of pointers so the pointer is copied.
<mrvn>
you were right
<mrvn>
So an array just increases the reference counter o every object at creation and reduces it when destroed. Would work.
<mrvn>
Would also double the size of int/float/char arrays. add 4 byte per object in general.
<mrvn>
I thing having 2 bits per object stolen for the GC is better.
<Smerdyakov>
Reference counting is a slow bastard.
<mrvn>
tags cost time too.
<Smerdyakov>
Copying collection can be done with almost zero overhead using existing virtual memory hardware.
<Smerdyakov>
Copying collection, the standard family of garbage collection algorithms used for ML.
<Smerdyakov>
You collect garbage by copying live data to a new memory space.
<mrvn>
you still need to know whats a pointer.
<mrvn>
You save the coloring bit, thats all.
<Smerdyakov>
Yes, but you can infer that from the types in your code.
<Smerdyakov>
You can hunt for papers on tagless garbage collection for more ifno.
<Smerdyakov>
info
<mrvn>
Smerdyakov: how so?
<Smerdyakov>
For instance, there's no need to tag values stored in registers or on the stack.
<Smerdyakov>
Since you always know which are pointers.
<mrvn>
a { a: int; b; int list; } will be a pointer and the GC won't know it contains an int and another pointer.
<mrvn>
in memory that is.
<Smerdyakov>
I don't know too much about the details, but I do know that "tagless garbage collection" is somewhat of a research area with papers on it.
<mrvn>
If you box ints then its easy.
<Smerdyakov>
But for your example, if this record is referenced by a register, then it is possible to tell the garbage collector its layout.
<Smerdyakov>
Without needing to store anything special in the register.
<Smerdyakov>
You just need a mapping from registers to types available whenever needed.
<mrvn>
Smerdyakov: sure. but it might be deep deep down im memory.
<Smerdyakov>
Right, which is where I don't exactly know how this works.
<Smerdyakov>
Though I have worked on the middle-end an SML compiler that does not box integers.
<Smerdyakov>
Or tag them, I mean.
<mrvn>
You can do speculative GC. If it points to somewhere the GC has objects assume its a pointer.
<mrvn>
Thats how GCs for C/C++ work usually.
systems has joined #ocaml
<Smerdyakov>
I'm pretty sure that's not how "tagless garbage collection works," but I must go now. You can find papers online if you care.
<mrvn>
not, realy, my pizza is done now.
<Maddas>
hm
<Maddas>
haha mrvn
<Maddas>
is there any Ocaml->C converter?
<Maddas>
The code needn't be fast, or nice, or anything.
<bk_>
why would you want that
<Maddas>
So I can code in O'Caml for my calculator.
<Maddas>
I seriously need something better than TIBASIC
<bk_>
aha
<mrvn>
write a gcc frontend for ocaml.
<Maddas>
I'm not very familiar with C, and don't plan learning C in the next year.
<mrvn>
shouldn't be too hard given obj-c, c++ and java
<bk_>
avoid it like the plague :p
<Maddas>
mrvn: it always sounds so easy on IRC :)
<mrvn>
if you don't know C your screwed :)
<Maddas>
:(
<bk_>
yes, but C sucks
<Maddas>
on it doesn't
<Maddas>
no, even
<mrvn>
You could learn TI asm and write an ocaml compiler for it.
<Maddas>
C is very useful in many places
<mrvn>
or a runtime system
<whee>
I think adding the TI asm backend would be the easiest
<Maddas>
mrvn: Uhm, that is above my head.
<Maddas>
I should just try to port Scheme or something then ;)
<whee>
what cpu does the TI use?
<bk_>
C, useful but ugly
<bk_>
imho at least
<Maddas>
not sure anymore, whee
<mrvn>
Its not that hard. We did a compiler for ppc for a subset of ocaml in a lecture at University.
<Maddas>
I think it's some dragonball or something
<Maddas>
mrvn: I'm not studying computer science :)
<Maddas>
so I don't really know too much about it, either. Still learning though :)
<Maddas>
or maybe I'll just try to survive without coding for my calculator at all.
<Maddas>
I should focus on more important and useful things :)
<Xcalibor>
ok, question
<Xcalibor>
i have foo x y, and I gotta apply it to each element of list ls with y = 300: List.map (foo _ 300) ls;; doesn't work (is there a placeholder for currying the function by the first parameter?)
<Maddas>
type mat = { n:int; m:int; t: float array array };;
<Maddas>
Why could I modify the elements of t later on? t isn't declared mutable after all
<whee>
Maddas: you can't modify the array, but you can modify the elements
<whee>
you can't go and create a new array and assign that to t, for example
<Maddas>
I see, so that's a feature, not a bug :-)
<Maddas>
Just was unexpected, thanks.
<whee>
well I believe the array works with references, so you can modify those
<whee>
a functional array would be pretty slow
<Maddas>
What do you mean? :)
<Maddas>
I agree.
<Maddas>
I just wondered, that's all.
systems has quit [Read error: 110 (Connection timed out)]
<Xcalibor>
ok. foo x y -> function x -> function y -> right?
<mrvn>
A functional array has to be copied for every change.
<mrvn>
You can download a functional array module for ocaml.
<Maddas>
It's ok! :)
<mrvn>
Xcalibor: ??
srv has quit [Read error: 104 (Connection reset by peer)]
<Xcalibor>
yes?
<Xcalibor>
i'm just thinking... ocaml functions only have an argument
<Xcalibor>
Fx... Fxy is actually (Fx)y
<Xcalibor>
right?
<pnou>
yep
<pnou>
this called curryfication
<pnou>
this is called curryfication
<Xcalibor>
then there's no way to curryfy F by the x argument, like in Haskell
<pnou>
hu? you don't need to curryfy in haskell
<Xcalibor>
but I may want to...
<Xcalibor>
i have a list of balues I want to apply to foo x y when y = y0
<Xcalibor>
values, I mean
<pnou>
you mean partial evaluation?
lophty_ has quit [Read error: 54 (Connection reset by peer)]
<Xcalibor>
yup
<Xcalibor>
it's the same, right?
<pnou>
no
<Xcalibor>
how come?
<pnou>
curryfication is the process to transform a function with n arguments to a function of function of function...
<pnou>
decurryfication is the reversed process
<pnou>
and partial evaluation is an evaluation (which is partial :-) of a curryfied function
<Xcalibor>
mmm... Fxyz -> (Fxy)z is curryfication and there's no decomposition in function -> function -> fun...
<Xcalibor>
anyway...
<pnou>
(Fxy)z is not curryfication, (Fxy)z has meaning because F is curryfied
<Xcalibor>
ho can I apply foo x 300 to ls = [1;2;...]?
<pnou>
(fun x -> foo x 300) ls
<Xcalibor>
List.map foo ls doesn't work... and I cannot put (foo _ 300)... and if I put (foo 300) it will be meant that x = 300 and it's the second parameter the one that's bound
<whee>
Xcalibor: List.map does what you want
<Xcalibor>
okay, it worked, thanks :-)
<whee>
err, bah
<whee>
I missed pnou's line :|
<Xcalibor>
(fun x -> foo x 300) is a kind of lambda, right?
<pnou>
right
<whee>
yes, it's an anonymous function
<Xcalibor>
excellent, I undeerstand now..
<whee>
if I were you, I'd just rip off a few of haskell's prelude functions like swap :)
<whee>
let swap f a b = f b a
<whee>
heh
<Xcalibor>
whee: the whole of Haskell prelude, if I could ;-)
<whee>
I think I was going to do that at some point, but decided not to
<whee>
just port every function from haskell that would work