- Feature Articles
- CodeSOD
- Error'd
- Forums
-
Other Articles
- Random Article
- Other Series
- Alex's Soapbox
- Announcements
- Best of…
- Best of Email
- Best of the Sidebar
- Bring Your Own Code
- Coded Smorgasbord
- Mandatory Fun Day
- Off Topic
- Representative Line
- News Roundup
- Editor's Soapbox
- Software on the Rocks
- Souvenir Potpourri
- Sponsor Post
- Tales from the Interview
- The Daily WTF: Live
- Virtudyne
Admin
Admin
Admin
I shortened things up slightly, and for grins and giggles threw in my Reverse method.
Admin
Tokenize on (IV, IX, I, XL, XC, X, CD, CM, C, D, M), map to (4, 9, 1, 40, 90, 10, 400, 900, 100, 500, 1000)... ?!
Admin
Perfect. But what's the underscores for?
Admin
Admin
uberadmin@subdesk:~/kindergarden> expr $(sed 's/IV/4 + /ig; s/IX/9 + /ig; s/IL/49 + /ig; s/IC/99 + /ig; s/ID/499 + /ig; s/IM/999 + /ig; s/XC/90 + /ig; s/XD/490 + /ig; s/XM/990 + /ig; s/CD/500 + /ig; s/CM/900 + /ig; s/VI/6 + /ig; s/VII/7 + /ig; s/VIII/8 + /ig; s/I/1 + /ig; s/II/2 + /ig; s/III/3 + /ig; s/V/5 + /ig; s/X/10 + /ig; s/L/50 + /ig; s/C/100 + /ig; s/D/500 + /ig; s/M/1000 + /ig; s/$/0/;' <<<mcmlxxxix ) 1989 uberadmin@subdesk:~/kindergarden> !
Admin
If you know Haskell, functional constructs are natural. Just because many programming languages don't offer such constructs doesn't mean they are unnatural. The idea that someone who doesn't have proper training can write decent code is ridiculous on its face, as repeatedly demonstrated on this site. I don't know Haskell, but I know LISP, and I immediately knew what foldl must mean, even though LISP is not really a functional language at heart. But then I know more than a Joe Random Coder, perhaps.
If you seriously think that lowest-level-of-abstraction code that only uses "natural" constructs from Algol is best for maintenance, you must have not ever seen how complex systems can benefit from high level abstractions available in the programming language used. I've seen both Caml and Erlang source that would grow at times by an order of magnitude if ported to any of the Algol-like languages.
Admin
root@box:~/tmp> expr $(sed 's/I([VXLCDM])/-1 + \1/ig; s/V([LCDM])/-5 + \1/ig; s/X([LCDM])/-10 + \1/ig; s/L([DM])/-50 + \1/ig; s/C([DM])/-100 + \1/ig; s/I/1 + /ig; s/V/5 + /ig; s/X/10 + /ig; s/L/50 + /ig; s/C/100 + /ig; s/D/500 + /ig; s/M/1000 + /ig; s/$/0/' <<<mcmlxxxix ) 1989 root@box:~/tmp>
Admin
root@box:~/tmp> expr $(sed 's/I([VXLCDM])/-1 + \1/ig; s/V([LCDM])/-5 + \1/ig; s/X([LCDM])/-10 + \1/ig; s/L([DM])/-50 + \1/ig; s/C([DM])/-100 + \1/ig; s/M/DD/ig; s/D/CCCCC/ig; s/C/LL/ig; s/L/XXXXX/ig; s/X/VV/ig; s/V/IIIII/ig; s/I/1 + /ig; s/$/0/' <<<mcmlxxxix ) 1989 root@box:~/tmp>
Admin
root@box:~/tmp> sed 's/M/DD/ig;s/CD/CCCC/ig;s/D/CCCCC/ig;s/LC/L/ig;s/C/LL/ig;s/XL/XXXX/ig;s/L/XXXXX/ig;s/VX/V/ig;s/X/VV/ig;s/IV/IIII/ig;s/V/IIIII/ig;s/I/I /ig' <<<mcmlxxxix | wc -w 1989 root@box:~/tmp>
Admin
root@box:~/tmp> tr /c-x/ /C-X/<<<mcmlxxxix|sed 's/M/DD/g;s/CD/CCCC/g;s/D/CCCCC/g;s/LC/L/g;s/C/LL/g;s/XL/XXXX/g;s/L/XXXXX/g;s/VX/V/g;s/X/VV/g;s/IV/IIII/g;s/V/IIIII/g;s/I$//g'|wc -m 1989 root@box:~/tmp>
Admin
In Haskell, "mapM_" is "foreach". Their "foldl1" is very different concept.
For the list (1, 2, 3, 4) and the functions f(x) and g(x, y); "f(1); f(2); f(3); f(4);" is very different conceptually from "g(1, g(2, g(3, 4)));".
Perhaps you need to read a book about Haskell?
So you're saying that for the list (1, 2, 3, 4) a real person wouldn't do "3 + 4 = 5", then "2 + 5 = 7" then "1 + 7 = 8" to get the sum? You're saying that a real person would assume addition is an operator and not a function? You're saying a real person would do something like "temp = list.next(); while(list.hasNext) { temp += list.next(); }"?
You're saying a real person wouldn't do anything like foldl1, but you thought they might because you don't know how foldl1 works?
What I said was "Haskell is poo because it forces people to use recursion". You replied with "modern compilers can do tailcall optimisation", completely missing the point that programmers still have to deal with the concept whether it makes sense for their problem or not (regardless of what the compiler generates). I played along and asked for a disassembly of the Haskell code we were talking about, with the intention of either showing that Haskell failed to use tail recursion to remove all of the recursion from it's own library functions or that the generated code is a huge bloated mess anyway, and you missed the point there too and showed C code where the compiler did do tail call optimisation. I restated my request for a disassembly of the Haskell code in question, and you've failed to produce it again.
I'm not sure if, like me, you don't have Haskell installed on any of your computers and couldn't be bothered installing it (I couldn't blame you if that's the case), or if you're deliberately trying to avoid posting the disassembly because you're ashamed of it, or if you're honestly unable to follow the conversation.
Admin
Here's another cool feature: lambda forms.
This one's kinda cheating though, you're not supposed to make them recursive.
Also, check out my cool C one-liner:
Admin
For me (and I doubt I'm the only one here), inhaling toxic smoke seems natural. Does this mean inhaling toxic smoke actually is natural?
After you know Haskell (or some other functional programming language) functional constructs may seem natural to you, but they won't seem natural before you get used to them, and won't seem natural to anyone else who hasn't become used to them.
For an ideal language, you wouldn't have to get used to anything before it seems natural. There isn't a language that comes close to this (and I doubt there ever will be), but some are closer to this ideal than others.
Admin
LOL, what? Did you look up "foreach in Haskell" on Google, read something about mapM_, and now think you're an expert on functional programming?
This will probably go way over your head, but mapM_ maps a function returning a monad over a list, and returns a monad containing the empty tuple. It behaves roughly foreach-loop-like only for IO, and does something wildly different in e.g. the Maybe or list monad (fun exercise: see if you can find out what).
foldl1 corresponds to the following foreach loop (pseudo-code):
Most other common uses for a foreach are available as well. Having the different uses as separate functions makes reading code easier, as just the name of the function is enough to know what exactly is happening.
I'm very sorry, but you stopped making sense. Are you saying foldl1 starts from the right, even though the l stands for left? And what is the difference between an operator and a function in your mind?
Wait, so I misunderstood you, thinking you said Haskell code runs slowly, while you actually mean programming Haskell is too difficult for you? Instead of just clarifying what you meant, you decided you now need the assembly code generated from a Haskell program (without mentioning which program)? Is that it? Indeed, I don't have "Haskell" installed, as it's a programming language, not a piece of software, but I assume GHC will do? If so, here is the Roman numerals program in assembly form: http://pastebin.com/LNUSq68u Do let me know if either the compiler or the compiled source are not exactly what you wanted, and I'll see what I can do.
Admin
root@box:~/tmp> awk -vr=mcmlxxxix '{gsub($1,$2,r); }END{printf r}' <<<'m dd cd cccc d ccccc lc l c ll xl xxxx l xxxxx vx v x vv iv iiii v iiiii' | wc -c 1989 root@box:~/tmp>
Admin
Isn't the correct language for this problem Lingua::Romana::Perligata? That's a language that deserves its own wtf book!
Admin
root@box:~/tmp> awk -vr=mcmlxxxix '{gsub($1,$2,r); }END{print length(r)}' <<<'m dd cd cccc d ccccc lc l c ll xl xxxx l xxxxx vx v x vv iv iiii v iiiii' 1989 root@box:~/tmp>
Admin
If you can't handle recursion reasonably well, you must not be much of a programmer. If you've got tail recursion in a language then of cours you're going to use it - it's the total shit, and combining it with functional constructs that replace calls with their results makes for a really simple and easy time of it.
Shit, next you're going to tell me that obejcts are too hard.
Admin
All this talk about Roman Numbers reminds me that "MMX" is a trademark of Intel.
We now return you the regularly scheduled programming concerning Perl, Haskel, Caml, C, C++, Fortran, Basic, APL, and Lisp. Carry on!
Admin
Hey, you hyper meta functional, objectional uberinformationist, a COMPETITION here: can you post your roman->natural haskell code via 1 sms or 1 tweet in readable form like me with bash/awk? Correct code - no failed test cases allowed?
Admin
Whether or not MIM and the vast array of other disputed Roman forms are correct in some sense isn't relevant. Roman numerals are obviously going to be coming from human input, so we should be liberal in what we accept. What we output is debatable; personally, I think MIM is much more elegant and acceptable to most actual users of computer programs, as opposed to the long dead Romans.
It's funny to hear complaints about needing to know Haskell before understanding code written in it from programmers who would write while(*a++ = *b++); without a second thought.
Admin
Sure:
Not great code, and Haskell certainly isn't ideal for code golf, but it works.
Admin
Yes :-)
So, the exact same thing behaves wildy differently in different contexts?
More like:
Look at the "recursive C with function pointer" example above. It starts from the left, but (with "add()" as the function) the values on the right would be the first ones added.
You are right though - I don't know if foldl1 starts from the right (so that the left values are added first) or if fold1 starts from the left (so that the right values are added first). This also implies that the "recursive C with function pointer" example above may be around the wrong way.
Of course it's irrelevant what the order is. For the list (1, 2, 3, 4) a real person wouldn't do "3 + 4 = 7", then "2 + 7 = 9" then "1 + 9 = 10"; and they also wouldn't do "1 + 2 = 3" then "3 + 3 = 6" then "6 + 4 = 10". Try it on a calculator yourself and see how you do it - I'll bet you key in something like "1 + 2 + 3 + 4 =" (and rely on the calculator to remember its accumulator) and don't do "1 + 2 = " then "3 + 3 = " then "6 + 4 = ".
To understand the difference between what I meant by "function" and what I meant by "operator", try passing the address of the '+' operator to the "recursive C with function pointer" example above. You'd have to write a function that does nothing more than "return a + b;" and then hope the compiler is smart enough to optimise out your counter-intuitive folly.
I haven't said Haskell (or code generated by GHC if you'd like to be pedantic) is slow. Speed is relative, and I'm sure the generated code is quite fast when compared to some languages. Being about 36 times faster than Perl is quite an achievement (even if Intel Fortran and GCC's C are about twice as fast).
While I can confirm that this is bloated enough to have been compiled from Haskell, and can also confirm that it is part of the Roman Enumeration code; sadly it's incomplete. The interesting part of the code disappears into a "jmp _stg_ap_n_fast" that isn't present, and various other parts of the code aren't included either.
Admin
And now I have the 1 clincher that will ruin roman numerals for all of you:
No way to represent 0. This means no binary. All other arguments are invalid.
Admin
Interesting question. Monads are basically a way to have values with "context". This context can be failure (the Maybe monad), non-determinism (the list monad), contact with the outside world (the IO monad), and more. mapM_ executes all the "context", but returns no value. In the IO monad, this means it executes all the IO actions, and returns nothing interesting. This is more or less like a foreach loop doing IO and computing nothing in other languages. In the Maybe monad, mapM_ tries to compute all values, but only returns the context: whether one of them failed or not. In the list monad, it tries to compute all values, and sees if there is still non-determinism left. So, yes, in a way they're very different things, but the general idea is the same.
Yes, that is the recursive version. You seem quite fond of recursion!
Indeed! That's why "foldl1 (+) list", which means "throw a plus sign between the elements of the list", is more natural than a raw loop, where you explicitly write out all the steps.
Yes, but that's a C-specific concept. The only difference between an operator and a function in Haskell is the name (special characters or not), and that an operator is infix, while a function is prefix.
So, what, you now want me to give you assembly code for all libraries used?
Admin
There are some things that are naturally recursive (traversing hierarchical trees for example), and I have no objection to recursion when it's the right tool for the job. This is not the case here - if I actually saw that code in a project being used to add a list of numbers I'd submit it to TDWTF (but it is about as close as I can get to mimicking Haskell's foldl1 (or foldr1?) in C).
http://zvon.org/other/haskell/Outputprelude/foldl1_f.html says: "it takes the first 2 items of the list and applies the function to them, then feeds the function with this result and the third argument and so on."
If the function you use has side effects, then it seems obvious to me that it isn't equivalent to inserting an operator between the elements of the list. Perhaps this is another case of "behaves wildly different when you're using the wrong concept to describe it".
Maybe "ghc -static -optl-static" would help with the missing pieces, while hopefully avoiding a lot of unnecessary/unused code.
Admin
My 5 minute attempt with handling for invalid values (e.g. IIIII).
Admin
Admin
Yes lack of think is causing major problems in universe.
Admin
Admin
%m = qw/I 1 V 5 X 10 L 50 C 100 D 500 M 1000/; @n = map {$m{uc($)}} split //, $ARGV[0]; $r+=$n[$]*(($n[$+1] > $n[$]) ? -1 : 1) for (0..$#n); print $r , "\n";
Admin
Why wouldn't you use a for loop to implement foldl1 instead of recursion? In what way does your code differ from mine? Haskell has implemented foldl1 for you, so you don't need to worry about the implementation details. When you're using a fold, you're not using recursion. A for loop in C is implemented with jmp, but I'm not saying using a for loop means using goto.
What? Functions don't have side effects in Haskell. I hope you see how "a + b + c + d" is equivalent to "((a + b) + c) + d". It is the way most people would calculate it if they have no calculator, and it is also the way both C and Haskell will actually calculate it. If functions and operators could have side effects, say incrementing a variable "count", both "a + b + c + d" and "foldl1 (+) [a, b, c, d]" will result in count being incremented by 3. Or are you saying only functions can have side effects, while operators can't? That's not even true in C, if you think about the ++ and -- operators.
Oh, you want me to actually disassemble the entire executable, not just my own code? Have fun with it: http://dl.dropbox.com/u/24516255/rom2num.asm
Admin
And he totally missed that there are two ways to say 4: "IV" and "IIII"
Admin
"I can only hope that the powers-that-be will determine that we are ineffective at training and shift the responsibility of teaching programmers to program to corporate training."
Well, that would require HR to do something constructive for a change, instead of merely continuing to justify their existence. They're gods you know, and so much more efficient and knowledgeable than any IT person ever could be.
Admin
Admin
Of course there's a way to write zero. It's the representation made up of everything from the following colon to the end of the line:
That is, don't write any Roman numerals. That's zero.
This does, of course, create the problem that there's no clear way to tell whether you mean the number zero, or you don't mean to convey any number at all. Of course we can't be too hard on the Romans: the idea of distinguishing a string with zero characters from a null string (or nothing string for you VB folks) is pretty recent, and still continues to confuse many programmers.
Reminds me: In the book "Lest Darkness Fall", there's a seen where a time traveller is trying to explain the value of the digit 0 to people who use Roman numerals. One of them asks in bafflement, "You have a symbol for nothing?" And the time traveller replies, "Why not? You have a word for 'nothing'." (Quoting from decades-old memory, excuse me if it's not an exact quote.)
Admin
Those who can, do. Those who can't, teach. Those who can't teach, recruit teachers.
Admin
I didn't use a for loop in that C example because I was trying to mimic Haskell, and therefore trying to avoid the use of mutable variables.
I probably should have made that clearer:
D'oh - sorry, I'm too used to useful languages. Can a function use a monad (or whatever they call their "things that do have side-effects that aren't functions but were necessary because the language designers removed required functionality and had to reintroduce it as something different for their bait and switch trick to work")?
And I hope you'll be able to see that this "insert the operator" description only works to describe a limited number of cases that (I assume) foldl1 supports. E.g. when the function is "return a + b;" or "return a - b;", but not when the function is "return a / (a + b);" or even just "return b - a;".
Hehee - knowing that horrendous mess came from just one line of Haskell made me laugh more than the original article did. Perhaps you could improve performance and executable size by replacing the one liner with:
Admin
Don't try to "mimic" Haskell in C, C wasn't designed for functional programming. If I tried to mimic C code in Haskell, the result would be equally messy. The C implementation of foldl1 would be a foreach loop, not recursion. The Haskell implementation uses recursion. This is fine: the underlying implementation does not matter to an everyday programmer, as long as the result is the same.
Yes, a function can use a monad.
No.
Haskell didn't "remove" required functionality and "reintroduce" it using monads. Haskell introduced monads, and got that required functionality (and more) for free, where other programming languages have a half-working implementation for some of the things monads can do.
Indeed, foldl1 is more powerful. In general, it's equivalent to the foreach loop I mentioned earlier:
For every left-associative binary operator, that's the same as just inserting the operator. In other cases, it's equivalent to a foreach loop, so it's just as "natural" as just writing that loop out, but a lot easier to read.
Glad I made you laugh. Look, if you want to argue that compiled Haskell code is a mess, the argument is over and you win. Obviously it is. It has its own little "runtime" to support lazy evaluation. Try to implement lazy evaluation in C, and see if you can do it in a cleaner way than the GHC people did. But anyone programming today that thinks executable size and performance are more important than maintainability and ease of programming, should not have a job with computers.
Admin
Admin
Depends on the circumstances. When something is a predictable and expected occurrence, e.g. there's no more data to read, returning a value that indicates that is preferable to the expense of throwing an exception.
Methods and properties that return bool often go hand-in-hand with ones that generate exceptions. Methods like int.Parse() in .NET have a corresponding int.TryParse() for a reason. Sometimes you don't know if your input is actually a valid value for the method; the Try* methods parse the input without generating an exception if it's not valid. Similarly Stream derived classes have things like the "bool CanRead" properties so you can avoid the exception that would occur if you did Read() on a stream that can't be read from.
If you have a method that has the possibility to generate an exception, make sure you provide a way of avoiding the exception.
Admin
Any bets on how long before briverymouse figures out he's being trolled?
Admin
Has this person EVER interacted with women?
I) Manipulation, via the emotions, is so common as to render this example ludicrous in itself.
II) Exploit, just look at dating and the common assumption that the man will pay.
III) Attack; apparently they've never been to a divorce-court. More oftan than not, the woman is downright vindictive.
Admin
i think you meant dickweedal pedantry
Admin
TRWTF is that his "code" counts as "managed to solve the problem"...
Admin
Almost, this will work if you only set LASTNUM = VALUE when LASTNUM != VALUE
Admin
Ok, this is a lengthy one, but just for the fun accepts ANYTHING remotely looking like a roman number (ignoring all non-roman-numerical characters) -- and also returns the canonical roman form.
Well, i still like C ...
Admin