<optiz0r>
I think it's because it doesn't get sent the output from the terminal unless I hit enter after my character, but then it's received two chars, t and \n. So I guess input_char or scanf("%c") is just taking the latter?
<optiz0r>
At least, that eplains why taking %c%c and throwing away the second one seems to fix it
<julm>
I don't think there is a buffering at the terminal level, though
<julm>
I think it's scanf that is waiting for the \n
<optiz0r>
That would make sense for what I've got at the moment. Even with input_char it would hang until I hit enter though
<optiz0r>
oh well, it does seem to be working now, so I won't fuss over why too much :)
<optiz0r>
I think my last remaining issue is that the scanf is waiting for input before my prompt is being printed, so the user has no idea what they're being prompted for. If I can fix that, then I can write up a report of what I've done and move onto the next piece of work :)
<julm>
optiz0r: could we have a self-contained version of your code?
<optiz0r>
to execute? a tarball of the directory ok?
<julm>
for instance
<thelema>
optiz0r: flush the output channel
munga has joined #ocaml
<optiz0r>
thelema: "flush stdout"? I added that after the printterm and before the scanf, but no joy
<optiz0r>
when you run it, it'll sit there waiting for the input. typing 0\n will do it. it should print char: 0, input port(0002)>, 0 : Nat. The intention is for the "input port(0002)>" line to appear before it waits for input.
<julm>
hum it's %! to flush with printf no?
thrasibule has joined #ocaml
<optiz0r>
swapping `flush stdout;` for `printf "%!";` doesn't fix
<julm>
let pr = Format.print_string
<julm>
hm
<julm>
Format.print_flush
<julm>
use that ^ perhaps
<thelema>
how are you printing?
<thelema>
julm: yes, if you're using Format, there's a different flush needed
<julm>
Format.print_flush seems to do it
<optiz0r>
julm: When I call Format.print_flush, I get a compiler warning: Warning F: this function application is partial, maybe some arguments are missing.
<mrvn>
.oO(It is a coloring book. Get out your red pen. :)
rwmjones_lptp__ has joined #ocaml
rwmjones_lptp_ has quit [Network is unreachable]
ksson has joined #ocaml
_unK has quit [Remote closed the connection]
rwmjones_lptp_ has joined #ocaml
<rwmjones_lptp_>
derdon, originally that page was static HTML. When we converted it to a wiki I'm afraid we lost those annotations.
rwmjones_lptp_ is now known as rwmjones
<derdon>
rwmjones: I see
<derdon>
rwmjones: are you the maintainer of this wiki?
<rwmjones>
it's maintained by the community
<derdon>
rwmjones: I want to translate some chapters (or maybe all of them) into German anytime
_zack has joined #ocaml
<rwmjones>
derdon, /msg me your email address & I'll send you an invite
<derdon>
done
rwmjones_lptp__ has quit [Read error: 101 (Network is unreachable)]
thrasibule has quit [Read error: 110 (Connection timed out)]
ikaros has joined #ocaml
[df] has left #ocaml []
<Leonidas>
derdon: wth are you doing here? ;)
<derdon>
Leonidas: disturbing :)
<derdon>
Leonidas: I hoped that here are many users asking and answering questions, but it's so quiet here
<derdon>
I thaught I could learn while listening to others who need help
<Leonidas>
derdon: obviously, you're stalking me in my functional lair - but I'm not gonna give you my lambda. My preciousssssss
<Leonidas>
derdon: weren't you rather on the way to learn haskell?
<Leonidas>
Oh, there you have your question...
<derdon>
Leonidas: No, I think haskell is yet to difficult for me
<derdon>
and OCaml is prettier :)
<Leonidas>
I am writing an unittest and want to print the results if not equal. oUnit supports this but needs a function with the signature 'a -> string
<orbitz>
typeclasses keep on puling me back to haskell
<Leonidas>
But I have an int - how can I construct a function that dispatches on the type and thows everything not int away?
<orbitz>
Leonidas: what do you mean?
<Leonidas>
derdon: while I do like ocaml, the syntax is killing me.
<Leonidas>
derdon: I just hate the whole module/sig/with type thing.
<Leonidas>
and I am pretty sure I haven't even seen all
<derdon>
as yet, I hate nothing about OCaml
<Leonidas>
While, OTOH, I just love guards and like that the language has an official macro system.
<Leonidas>
orbitz: my problem is that printer is int -> string and not 'a -> string
<orbitz>
Leonidas: do you have an actual testcase?
noj has quit ["leaving"]
noj has joined #ocaml
<det>
I think type classes are the best thing ever
<det>
... but Ocaml as a whole is nicer than Haskell
<det>
I also dislike Ocaml syntax
<det>
I prefer Python's syntax to anything else
<mrvn>
det: write a camlp4 module
<det>
Can you override the lexer in camlp4 ?
<det>
For python syntax, you have to insert indent/newline/dedent tokens
<mrvn>
I bet
<orbitz>
eeep I like Python a lot but the syntax is one thing that I am not a big fan of
<orbitz>
if Python had layouts like Haskell I think i'd like ita lot more
<det>
Why are layouts better?
<orbitz>
Because there are places where the syntax is an impediment, a la lambda's
<mrvn>
What I find bad in python is that if you change the level of indentation it is easy to mess it up. You realy need an editor that and indent/deindent a block at once.
<det>
python allows you to ignore indentation inside ()
<det>
a = (
<det>
...
<det>
)
<orbitz>
not with code...
<det>
I guess, ya
<det>
Can you give an example that would be hard to express in python syntax
<orbitz>
I also wish more code evaluated to a value in Python too
<orbitz>
so i could do a = if foo then bar else zoom
<det>
oh, sure
<det>
I agree with that
<orbitz>
dont' get me wrong, Python is my most used langauge right now
<orbitz>
And I do love code HAVING to be indented properly and consistently, I just think it's too constrictiev sometimes
<orbitz>
and when you use a language a lot the littlet hings are what bother you the most
<det>
I am trying to design a Python-like syntax for a ML now
<mrvn>
let a =
<mrvn>
.value value value
<orbitz>
det: what would the benefit be?
<mrvn>
in
<mrvn>
.code code code
<det>
orbitz, easier to read and code
<det>
mrvn, this is in response to me ?
<mrvn>
yep
<det>
what is .value ?
<orbitz>
det: Hard for em to relate tehre since i find ML a pleasure to read. but aren'tyou going to lose a lot tryign to cram ML code into Python-like syntax?
<mrvn>
The differenze for ocaml would be rather minor though as most of the time you don't have a sequenze of expressions.
<det>
mrvn, I dont understand your example
<mrvn>
Only place you would rely on indentation would be where you have begin/end now.
<mrvn>
det: . being the indentation token
<det>
mrvn, can you give a simple example that runs in the repl
<mrvn>
det: nope. you have to write the lexer/parser first
<orbitz>
det: he is talking about your syntax idea
<det>
I mean
<orbitz>
he isn't talking about how it currently wroks
<det>
that runs fine as ocaml syntax
<det>
but would be hard to express with indentation syntax
<mrvn>
another example:
<mrvn>
f x
<mrvn>
y
<mrvn>
g x
<mrvn>
y
<mrvn>
Instead of f x y; g x y
<orbitz>
det: personally, I just don't see what real value python-like sytnax would have for ML, if anything I think it woudl be a limitation
<orbitz>
det: meh i have a hard time agreeing that is necessiarly more powerful. it is different i will agree, but it's a balance
<det>
I mean
<det>
def sum(list): List.fold_left((+), 0, list)
<det>
than
<det>
let sum list = List.fold_left (+) 0
<det>
or in Ocaml:
<orbitz>
current syntax gives me a very concise consistent syntax for doing function calls and all that, and i can wrap it in another function trivially if I need more power so I have best of both worlds curerntly IMO
<mrvn>
but the () are completly unneccessary
<det>
my mind is scrambled
<orbitz>
i don't really liek ()'s :)
<det>
I keep making errors
<orbitz>
I think that is one reason Scala is such shit to read. all teh ()'s
<orbitz>
and teh type annotations ina ll the wrong places, but that's a diff problem
<det>
let sum = List.fold_left (+) 0
<det>
let sum list = List.fold_left (+) 0 list
<det>
of those 2, I prefer the latter
<det>
it is obvious
<mrvn>
det: what if sum is polymorphic?
<det>
then you must use the latter anyways :-)
<mrvn>
like: print_int (sum f1 x); print_int (sum f2 x y z)
<orbitz>
can you decouple type annotation from defintion in ocaml ilke in haskell?
<det>
orbitz, sure
<orbitz>
what's it look like?
<mrvn>
The number of items in the tuple might be dependent on the arguments
<det>
orbitz, you mean in my imaginary language ?
<orbitz>
no, in Ocaml...
<det>
you can not
<orbitz>
ok
<orbitz>
det: the latter tends to not be a problem for me as I am usually just looking at the type of a function when pokign around code, nto reading teh source
<det>
mrvn, you can do the same tricks with nested tuples
<mrvn>
det: that would be inconsistent
<det>
it would not
<orbitz>
example?
<det>
not if , was a pair operator :-)
<mrvn>
ah, you mean you only have tuples instead of n-tupls
<det>
mrvn, I think you once posted a curried printf and I converted it to nested pairs
<det>
yes
<mrvn>
ineficient
<det>
nope
<mrvn>
yes
<det>
if you have a monomorphizing compiler, you can flatten it
<mrvn>
.oO(Yeah, lets design something bad into the language so the compiler can optimize it away again. :)
<det>
that is not designing something bad
<det>
it is designing something simple
<det>
you could say the same about closures
<mrvn>
det: In ocaml the args are flattened by default.
<det>
yes
<det>
that is the _real_ reason for currying in Ocaml, IMO
<det>
not because it is expressibe
<det>
expressive*
<det>
but because it aids the compiler (tuples always allocate in Ocaml)
<mrvn>
no, that is because you have n-tupels.
<det>
n-tuples doesnt help in ocaml
<mrvn>
they give you O(1) access to arguments.
<det>
flattened pairs offer the same
<det>
but are also consistent throughout the whole language
<det>
and let you return multiple values with allocating
<det>
without*
<mrvn>
how do you eliminate the allocation?
<det>
in my imaginary language ...
<det>
tuples would be stack allocated, and passed by copying
<mrvn>
and how do you flatten the return tuples?
<det>
much like a struct in C
<det>
if you want heap allocation, you enclose in {}
<mrvn>
det: then you have n-tuples just like ocaml.
<det>
yes, after monomorphization
<orbitz>
wiat s you have to care about heap vs stack?
<mrvn>
and with stack alocation you get problems with values escaping their scope.
<det>
not before
<det>
orbitz, try writing a competitive performance complex number library in Ocaml
<det>
def swap(a, b): b, a
<det>
something like that in Ocaml always causes an allocation
<mrvn>
allocation is cheap
<thelema>
det: you can't do that in ocaml, as it doesn't have references of the kind you want.
<det>
you can certainly write:
<det>
let swap (a, b) = b, a
<thelema>
mrvn: is cheap compared to some things, not cheap compared to high-performance math code.
<mrvn>
The only way you can remove the allocation is if you can proof that the input tuple can't be referenced by anything else so it can be reused.
<thelema>
det: yes, but this won't change the original values passed in
<thelema>
of course this is a good thing in the functional world.
<det>
thelema, neither would my version
<mrvn>
det: The expensive part in complex numbers is not the allocation but the boxing.
<thelema>
but for really high performance, that's what you want to do.
<det>
mrvn, yes, when I say allocation, I mean boxing
<det>
thelema, a = swap(a)
<det>
thelema, with my version, the compiler can generate fast code
<mrvn>
det: then write an optimizer for ocaml that does a better job of unboxing floats, preferably across functions or even modules.
<det>
it doesnt even have to be the same variable name
<det>
mrvn, I dont beleive that is the right approach
<det>
mrvn, I think monomorphization is the right approach
<det>
combined with the programmer ability to choose stack/heap representation
<mrvn>
det: that is a different problem
<thelema>
and that's what you have to do in order to get what you want. And with ocaml's limited representation list, monomorphization is almost practical.
<thelema>
stack/heap representation should be exposed? huh?
<mrvn>
det: programmers will choose stack/heap representation wrong and all the iteresting cases you can't proof.
<det>
so better to just make everything heap ?
<mrvn>
det: that is the trivial and safe way.
<mrvn>
Then you can optimize things onto the heap where you can proof it is safe.
<orbitz>
isn't thsi what HLVM is tryign to solve?
<thelema>
That's the only way to do it without 1) codesize explosion in the general case or 2) runtime generation of the needed code
<thelema>
not runtime...
<thelema>
whole-program generation of needed code
<det>
Yes, whole program generation
<det>
but
<det>
that doesnt preclude incremental compilation
<mrvn>
That is basically what c++ templates do and g++ needs a ton of memory and time to compile anything
<det>
templates arent the same thing
<mrvn>
The get compiler for every type they are used for. that is what you are talking about
<det>
monomorphization just means you must have either source or some IR for polymorphic functions
<det>
and generate them on demand
<det>
I mean, during compilation, based on dependencies
<det>
MLton is a special kind of whole-program compiler that must recompile the whole program every time
<mrvn>
det: Where do you think monomorphization would make things faster?
<thelema>
whenever a polymorphic function gets called, generate the specialized version of that function for the needed types and call that?
<det>
thelema, pretty much, but only generate 1 function per set of types
<mrvn>
det: you can't if you have incremental compilation
<det>
you can
<mrvn>
how should compiling B.ml know that A.ml already instanciated some type?
<det>
implementation detail
<mrvn>
det: no, impossible to do cleanly
<det>
ok:
<det>
a folder of object files
<det>
named by hash
joewilliams has joined #ocaml
<mrvn>
det: for each project? each directory?
<thelema>
one could append the pre-compiled versions of a function to the .o file for the original function.
<det>
mrvn, it's not a hard problem, that is just 1 way to do it
<mrvn>
thelema: that would alter the timestamp and you don't have write permissions to /usr/lib/
<thelema>
when you generate a specialized version of a function, put it where the original was.
<thelema>
If you can't append, then you generate your own local copy.
<det>
anyways
<mrvn>
thelema: so we are back to generating lots of local copies
<det>
mrvn, so ?
<mrvn>
slow
<thelema>
mrvn: in some cases. For code that's part of your project, not so much.
<det>
why is it slow
<det>
first compile maybe
<mrvn>
det: because you do it over and over
<det>
incremental compiles are fast
<thelema>
For global libraries, you could pre-generate all combinations, so they're already ready.
<mrvn>
for some value of "all" that includes commonly used types
<det>
all combinations = infinite :-)
<det>
I see no problem with slowing down the first compilation of a project a small bit
<det>
and it could even be avoided with some work
<thelema>
yes, using a small value of "all"
<mrvn>
det: then you combine this with inlining and you get an exponential increase in time and space
<mrvn>
c++ shows how bad this can go
<det>
mrvn, in theory you get the same from HM
<det>
MLton never had this issue
<mrvn>
thelema: I actualy think the "all" could be rather small. You only need to cover the primitive types and then maybe tuples, list and arrays of them. Anything more complex I doubt monomorphizing gains you anything. just ruins the code cache.
<det>
It has other issues, but not code-size blowup
<thelema>
mrvn: there's room for this kind of technique just like there's room for both native and bytecode ocaml
<mrvn>
thelema: not if it actualy makes things slower
<det>
mrvn, I dont think it would
<thelema>
this is ok if it's off by default until it's tuned to commonly make things faster
<mrvn>
det: you still haven't given ann example where it would help
<det>
I think it would simplify implementation and make things faster in general
<mrvn>
det: simplify? never
<thelema>
mrvn: the gitj people wrote a nice article about how they couldn't reach the performance of C-git in Java, partly because of boxing.
<det>
mrvn, says the guys who suggested improving Ocaml's cross module float unboxing
<mrvn>
And the GC must also be able to go through the stack and registers
<det>
there are a couple ways to solve that
<mrvn>
Say you have "let f x y = x +. y" then the compile should generate:
<mrvn>
f: put b info fp0, put b into fp1, call f_unboxed, box fp0 again
<det>
that should always be inlined reguardless :x
<mrvn>
f_unboxed: add fp0,fp1
<mrvn>
det: in this trivial case sure. but you get the principle.
<det>
that function can never allocate anyways
<mrvn>
det: x +. y allocates a float.
<det>
assuming boxing, yes
<det>
but i say that boxes dont need to be boxed
<det>
I mean floats
<mrvn>
they need to be when in memory.
<det>
why ?
<det>
GC can be solved without boxing
<mrvn>
so the GC can differentiate them from pointers.
<mrvn>
You need some bit somewhere that says "this word is not a pointer"
<det>
You can use the return address of the function to see what is on the stack and registers at that point
<det>
you need no such thing
<det>
you need a way to see what is in registers and stack
<det>
universal representation is 1 way of doing that
<det>
if your program is monomorphized, you can use the return address of the function
<mrvn>
det: registers are easy, FP registers are always floats. :)
<det>
or push something on the stack for each stack frame
<mrvn>
And on stack you still need to know which word is a pointer
<det>
yes, but like I say, you can figure that out in other ways
<det>
without ever boxing
<mrvn>
det: if you put a bitfield onto the stack that marks pointers I still call that boxing.
ski_ has quit ["Lost terminal"]
<mrvn>
I don't mean that you neccessarily need to allocate on the heap.
<det>
what if you use the return address
<det>
btw, I dont call that boxing
<det>
because it isnt boxed
<det>
either of them
<mrvn>
det: you mean the return address of the next stackframe to get the address of the function and then some static bitfield for that function describing the stackframe?
<mrvn>
I would think that is way to expensive
<det>
I mean:
<det>
every function knows the address it must return to
<det>
I mean
<det>
it knows the address after is is called, because that address is on the top of the stack or in a register or w/e (dependent on arch)
<mrvn>
sure
<det>
if your program is monomorphic, then from this address you can always find out the state of the function that called you
<mrvn>
And the GC can know that the function that includes the return address X will have a float, and int and a pointer on the stack.
<det>
yes
<det>
there are a couple of ways to lookup the types from this address
<mrvn>
Which is expensive as you need to first find the function containing the address (a function can have many) and then lookup the info for that function.
<det>
im not done
<mrvn>
Putting an extra word on the stack costs a little ram but you have all the info directly.
<det>
right, that is probably the best solution
<det>
... but
<det>
you can do it with no overhead
<mrvn>
Lets call that "tagged"
<det>
let's say that on x86
<mrvn>
det: you always have overhead. you can just choose between time and space
<det>
ok, I wll admit that
<det>
instead of using "call blah"
ski_ has joined #ocaml
<det>
you do this
<det>
sec
<Leonidas>
uhm, coming back to my original question from 2h ago: how can I write this printer function that handles 'a -> string ?
<det>
normal code for x86:
<det>
call someFunction
<det>
... rest of code
<det>
another scheme:
<mrvn>
Leonidas: Like Printf.printf with a format string or functional with CPS
<det>
push return_point on stack
<det>
jmp someFunction
<det>
jmp GC_blahpoint
<det>
return_point:
<det>
... rest of code
<mrvn>
det: with GC_blahpoint being the code that registers the pointers on the stack in case the GC runs?
<det>
using this scheme, the function knows that it can GC by jumping to the code at 1 word less than the return point
<det>
mrvn, right
<mrvn>
det: nice idea. That would "box" or "tag" the values through generating code.
<det>
its not my idea
<det>
it is from a paper
<mrvn>
det: skipp the "jmp" though. just put the address there.
<det>
only problem could be if call/ret is faster than jmp
<mrvn>
det: call does something else that jmp on many cpus.
<det>
call is simply:
<det>
push next address on stack
<det>
jmp
<mrvn>
det: totally cpu dependent
<det>
but there might be some kind of optimization in the silicon, I dont know
<mrvn>
det: Alpha for example doesn't have "call" at all.
<det>
I know ARM has something like call
<det>
and x86/x86_64,arm are the architectures that matter most right now :-)
<mrvn>
alpha only has "jmp where,when,return-addr" iirc
<det>
when?
<mrvn>
det: condition code in a register
<det>
oh
<mrvn>
jmp r0,r1,r29
<mrvn>
if "r1" is true then it jumps to r0 and puts the return address into r29
<det>
I think ARM let's you put conditions on all instructions, not just jumps
<Leonidas>
mrvn: Hmm, I'll probably do just that.
<det>
mrvn, what is r29 used for ?
<mrvn>
det: return address
<mrvn>
might not be r29 but there was some default register for the C ABI.
<det>
"return address" means "next instruction" ?
<mrvn>
det: yep
<det>
oh, ok
<Leonidas>
thelema: the more I use OCaml, the more I see how useful AAA is. But I'll go with Printf first.
<det>
can you jump without the third operand ?
<thelema>
Leonidas: as you will.
<mrvn>
det: for your code every function would end with "add #8,r29; jmp r29"
* Leonidas
wants AAA included into OCaml in the future, actually :)
<det>
mrvn, I am thinking about loops
<mrvn>
det: i.e. skip the GC_hunk and return
<thelema>
Leonidas: it won't happen even if 99% of ocaml users use it.
<mrvn>
thelema: not even for the modules that just extends the stdlib?
<thelema>
mrvn: yes
<mrvn>
thelema: is upstream so dead set to extending the stdlib?
<mrvn>
s/to/against/
<thelema>
Yes, because it means that INRIA maintains the code, as opposed to the community.
<Leonidas>
ah, thats annoying.
<mrvn>
Then I think at some point the community should just fork
<thelema>
We're nowhere near ready.
<Leonidas>
maybe that will happen someday. AAA paves the way by making ocaml more useful.
<thelema>
yes, the community may finally step up to the plate.
<mrvn>
Since we are on the topic of boxed floats. I was thinking that for a fractal programm instead of passing complex floats (26 + temp vars) around it might be better to create one float array with all the floats combined and work solely on that.
<thelema>
mrvn: = manual memory managementy
<mrvn>
Sure. but I know how many floats I need and it is the inner loop
<thelema>
This would work, but why write in ocaml in this case?
<thelema>
brb, lunch
<mrvn>
thelema: I have a 3x3 grid of points and 4 points in the middle for control purposes. I do a few iterations on the grid and then check if interpolating is close enough to the control points. If not I subdivide the grid and repeat for the 4 subgrids.
<Leonidas>
mrvn: but when I use Printf.sprintf I still can't use the function, because it expects int -> string and not 'a -> string.
rwmjones has quit [Read error: 60 (Operation timed out)]
<Leonidas>
Apparently, Printf is typesafe and Leonidas-proof :)
<det>
Leonidas, why do you need a function that is 'a -> string
ksson has quit ["leaving"]
<mrvn>
Leonidas: if you give sprintf an "%d" format then obviously it wants an int
<det>
If you want such a function, I can provide it to you, but I am afraid it wont be very useful
<mrvn>
Leonidas: a true "'a -> string" can only work with the memory representation of 'a. Not the real type.
<det>
let f x = "Im a string!"
<mrvn>
det: that does verry little with the representation. :)
<det>
I am trying to figure out why he needs such a function
<Leonidas>
det: because I want my test case to actually print the variable. And the type signature of the printer function I have to hook in is 'a -> string
<Leonidas>
Maybe I just rip off part of the AAA code :)
<det>
Leonidas, where are you hooking this in ?
<mrvn>
Leonidas: so the printer is ('a -> string) -> 'a -> string?
<Leonidas>
det: ounit
<det>
Leonidas, what call
<Leonidas>
mrvn: no, just 'a -> string
<Leonidas>
det: assert_equal
<mrvn>
Leonidas: you need to use a different one for each 'a you use
<orbitz>
det: it really takes no more than a few keystrokes to make 'and' into 'let'. I have no problem with this. and it results ina compiler error if you fail to