Formatting Decimals in Haskell

A formatting function to go from numbers like 333999333.33 to “333,999,999.33” in Haskell. Copes with negative numbers and rounds to 2 dp (easy to add a paramater for that should you wish).

Examples:

*Main> formatDecimal 44
"44.00"
*Main> formatDecimal 94280943.4324
"94,280,943.43"
*Main> formatDecimal (-89438.329)
"-89,438.33"
import Data.Graph.Inductive.Query.Monad (mapFst)
import List
import Text.Printf

formatDecimal d
    | d < 0.0   = "-" ++ (formatPositiveDecimal (-d)) 
    | otherwise = formatPositiveDecimal d 
    where formatPositiveDecimal = uncurry (++) . mapFst addCommas . span (/= '.') . printf "%0.2f" 
          addCommas = reverse . concat . intersperse "," . unfoldr splitIntoBlocksOfThree . reverse 
          splitIntoBlocksOfThree l = case splitAt 3 l of ([], _) -> Nothing; p-> Just p

If you know a simpler way or spot anything that should be done differently, please add a comment.

Speed Up Very Slow darcs Push/Pull

After investigating a lot of blind alleys I think I’ve solved a problem with pushing and pulling to and from a remote repository being very slow. darcs was issuing hundreds of scp commands just to push up a one line change. This seemed to be related to the _darcs/inventory file being a couple of thousand lines long (should be much smaller) on the remote repo.

In the final analysis my advice is very simple:

  • Make sure you have recently done a darcs tag
  • Issue a darcs optimize --reorder-patches command (the reorder patches part may be unnecessary and cause it to be much slower, but it worked for me although it took three hours).

This reduced push/pull time from 3 minutes to nearer 3 seconds.

AdBlock Plus

After reading A World of Endless Advertisements I thought it would be interesting to see the AdBlock Plus version next to the unblocked version.

SD Times with Ads
SD Times without Ads

How “ad-supported content” is supported without ads, I don’t know. But as Banksy says:

“Any advertisement in public space that gives you no choice whether you see it or not is yours. It belongs to you. It’s yours to take, re-arrange and re-use. Asking for permission is like asking to keep a rock someone just threw at your head.”

(Faintly amusingly I actually had difficulty writing this post because AdBlock blocked the images I was using because their name contained the word “ads”.)

Combining make and cabal

I had to integrate a haskell program into an existing make-based intrastructure this week. After a few false starts I managed to proxy to cabal through make with the following Makefile. I also added a feature to copy the binary created to a “bin” folder at the same level as the src folder. I’ve used the Haq example name from How to Write a Haskell Program and my cabal setup is similar to the one described there. Trying to compile Setup.lhs or anything more complicated is a mistake and I am assured that runhaskell is portable.

all:
	runhaskell Setup.lhs configure
	runhaskell Setup.lhs build
	cp dist/build/haq/haq ../bin/

clean: 
	runhaskell Setup.lhs clean
	rm -rf ../bin/*

Replace in Haskell

Haskell seems to be missing a String replace function. Text.Regex.subRegex seemed like overkill. So I wrote one. It actually works on any list, not just Strings.

replace :: Eq a => [a] -> [a] -> [a] -> [a]
replace [] _ _ = []
replace s find repl =
    if take (length find) s == find
        then repl ++ (replace (drop (length find) s) find repl)
        else [head s] ++ (replace (tail s) find repl)

Some examples:

*Main> replace "hello" "h" ""
"ello"
*Main> replace "hello" "l" ""
"heo"
*Main> replace "hello" "x" ""
"hello"
*Main> replace "100,000,000" "," "hello"
"100hello000hello000"
*Main> replace "100,000,000" "," ""
"100000000"
*Main> replace [1,2,3] [1] [9]
[9,2,3]
*Main> replace [4,5,6,1,2,3,7,8,9,2,3,6,5,4,1,2,3] [1,2,3] [10]
[4,5,6,10,7,8,9,2,3,6,5,4,10]

If this function is already in the standard libraries somewhere or if this can be improved in some way please leave a comment to let me know. Thanks!

Ubuntu Dapper is NOT debian-unstable

A cautionary tale about installing debian-unstable packages under Ubuntu Dapper.

I needed version 6.6 of the Glasgow Haskell Compiler and Dapper/Edgy only supply version 6.4.2. I found a mailing list post explaining that 6.6 was available under debian-unstable, which is what Ubuntu is based on. So I downloaded the .deb and tried to install it.

No dice. Requires a partcular version of libc6. So go grab that (BIG mistake – this is possibly the most central library in the whole system and switching versions of it was never going to be a good idea). Try to install, find a dependency (tzinfo), try to install the dependency and kapow – failed in mid-install! Tried to overwrite a file that dpkg thought belonged to the locales package.

Now, whatever I did I got something like this:

sudo apt-get -f install
Reading package lists... Done
Building dependency tree... Done
Correcting dependencies... failed.
The following packages have unmet dependencies.
  libc6: Depends: tzdata but it is not installable
  libc6-dev: Depends: libc6 (= 2.3.6-0ubuntu20) but 2.3.6.ds1-10 is installed
  libc6-i686: PreDepends: libc6 (= 2.3.6-0ubuntu20) but 2.3.6.ds1-10 is installed
E: Error, pkgProblemResolver::Resolve generated breaks, this may be caused by held packages.
E: Unable to correct dependencies

I tried every combination of: apt-get remove, apt-get install, dpkg -r and dpkg -i with each package name and variations on the package names as well as bare apt-get install -f and using –force and –purge and goodness knows what else (many thanks to the denizens of #ubuntu on freenode for their many suggestions). Whatever I did the system would just tell me it was queueing up to install the debian versions of ghc and libc6 and that it couldn’t work it’s way out of the dependency pickle.

Finally a knight in shining armour by the unexpected name of “crot” came up with this baby:

sudo apt-get install -f libc6/dapper

The /dapper forces the system to install the correct version even though the debian package is also called libc6. Thanks crot!

I leave this blog post for those who try something equally foolish. If you use a package from the wrong distribution or wrong version, this may help you out.

Ubuntu and AIGLX

Forget about Vista/Aero, just look at the visual abuses that are possible in the Ubuntu with AIGLX (coming as standard in Feisty in April 2007). Mostly pointless but tremendous fun.

(Mark Shuttleworth calls providing this kind of facility one of the challenges we need to overcome. He hopes to see usability/productivity enhancements as well as pretty bubbles and lines of fire. I hope so too.)

Column Width: What is the One True Way?

Should you limit the width of your source code? You can’t read code
that goes off the edge of your screen. So your font size, resolution
and monitor all combine to produce a point at which you must break (or
at least wrap) your lines of code.

I don’t like wrapping. Lines of arbitrary length that wrap wherever
I happen to have positioned the right-hand side of my window seem
messy.

Even if you have plenty of room for more columns, standardising on a smaller number means that when reviewing code
you can see changes side by side using a difference viewer.

Given that I am going to insert a line break somewhere in my code,
where should it go?

There are many possible answers.

COBOL allows approximately 66 characters for code (72 columns – space
for line numbers).

Fortran has 72 usable columns from a maximum of 80.

xterm and gnome-terminal (among others) open 80 columns wide by
default. So does emacs.

vim allows 8 columns for line numbers, leaving 72 usable columns on
a standard terminal.

80 columns was built in to Apple //e motherboard.

Sun’s Code Conventions for the Java Programming Language say:

4.1 Line Length

Avoid lines longer than 80 characters, since they’re not handled well by many terminals and tools.

Note: Examples for use in documentation should have a shorter line length-generally no more than 70 characters.

The linux kernel seems to mostly be broken at 80 columns but there are plenty of exceptions (91-column example):

File: linux/drivers/firmware/efivars.c
Line:  749
printk(KERN_ERR "efivars: Sysfs attribute export failed with error %d. ", error);

Some people definitely go wider than 80 columns.

If you want to be able to “> ” quote in an email on an 80-column terminal without wrapping, you’ll have to limit yourself to 78, or less for nested quoting.

GNUStep coding standards say 80 columns. So do other standards (cites printing as the reason, not screen space).

72 and 80 seem to have originated with punch cards, but are by far the most common standard. So, is 72 or 80 columns old-fashioned? Pointlessly restrictive? Or is it the One True Way? Make a comment and let me know what you think!

More than 46 Emails With eBay, or, the Dark Side of the Network Effect

I have exchanged approximately 50 emails with eBay over my latest bill of 1.57 GBP and a 5.00 GBP charge they added for direct debit payment being refused by my bank (it was automatically cancelled after 12 months of inactivity as is standard banking practice – eBay are well aware of this practice). The situation is still not resolved.

I couldn’t have had this experience with eBay if they weren’t (effectively) a monopoly. Almost no other company could be this daft and unresponsive and still expect my custom.

This is the dark side of the network effect: because it makes sense for everyone to be on one auction site, the top auction site quickly becomes the only auction site. Consider this my request for an eBay-killer!

The Emails

20 Oct – Invoice for 1.57 with note that it will be taken by direct debit shortly.

07 Nov – Email telling me my direct debit was declined and that I have been charged 5.00 and now owe 6.57.

I reply asking why. I also hook up my account to pay by PayPal in future as another email requests.

10 Nov – Reminder that I owe 6.57

I reply asking them to remove the 5.00 and take the 1.57 by PayPal any time they like.

15 Nov – They reply telling me my direct debit was declined.

I reply asking which bank the direct debit was with.

17 Nov – They reply a second time to my original reply with the same standard email.

I reply asking them to remove the 5.00 charge as I haven’t cancelled a direct debit and take the balance via PayPal as they can do at any time.

19 Nov – They send the standard direct debit failure message for a second time.

I reply asking which bank account they think they were taking from.

20 Nov – billing send me the invoice again.

I reply, getting somewhat frustrated, with a plea for help, my telephone number and a third request for more details on the direct debit.

21 Nov – They send me a standard reminder for payment, again.

I reply asking for the direct debit details for the fourth time.

21 Nov – Customer Support email me telling me they are happy to help and can explain everything. It’s because my direct debit was declined (no details)!

I reply asking for the direct debit details for the fifth time.

23 Nov – They send me a third standard reminder for payment (fifth, if you include invoices).

23 Nov – Customer support finally send me the details of the direct debit. I call my bank and discover that they cancelled the direct debit because of 12 months of non-use which is, “standard banking practice” and, “any company would know this”. So why did eBay try to take payment from a direct debit that they know had not been used in 12 months?

I reply asking why they have tried to take money from an out-of-use direct debit and asking for 5.00 credit.

23 Nov – They send me the same identical email a second time 7 minutes later.

26 Nov – They send me a completely blank email.

I reply asking them to try again!

27 Nov – They send the standard direct debit failure message for the third time.

I reply explaining about the direct debit cancelled as standard banking practice and asking for credit.

28 Nov – They send me a fourth standard reminder for payment.

I reply explaining the situation and asking for 5.00 credit.

29 Nov – Customer Support tell me they have passed the query to Billing.

I reply saying thanks.

29 Nov – They send me a bizarre reply telling me they are happy to have me as a member and wishing me, “Happy Trading!”

01 Dec – They send me a fifth standard reminder for payment.

I reply explaining the situation and asking for a 5.00 credit.

At this point they somehow wake up and realise they can take the money by PayPal. They take all 6.57.

03 Dec – Customer Support send me the “no instruction” email explaining why a direct debit might have been refused. Reason (1) is: “Direct Debits which have been out of use for a year or more may be automatically cancelled by your bank due to inactivity.” So they do know this happens! They just try to take payment anyway!

I reply explaining that reason (1) is the reason and asking for 5.00 credit.

03 Dec – They send me the standard direct debit refused email for the fourth time.

I reply explaining the situation and asking for 5.00 credit.

04 Dec – They reply to one of my emails asking for credit as if they haven’t read it and saying thanks for the payment it’s all sorted out now. They also tell me to disregard demands for payment because they are, “system generated”.

I am now in despair. I reply threatening Trading Standards and to contact the BBC’s Watchdog program. And explaining the situation, and asking for 5.00 credit.

05 Dec – They send me the direct debit refused email for the FIFTH time.

06 Dec – They send me the “no instruction” explanation email for the second time.

I flip out and send them a mostly-caps response begging for someone to understand me, or call me, or something. It contains the line, “COME ON I DARE YOU, SEND ME AN INTELLIGENT REPLY!”

07 Dec – Customer Support email me telling me that I will get a credit. Although they also suggest contacting my bank to find out why and include other information that is clearly redundant if they had read the email they are replying to I don’t care because I have finally made the breakthrough!

09 Dec – Customer Support reply telling me I will be credited 5.00 shortly and apologising for the delay.

I reply saying thanks.

10 Dec – Customer Support writes to me telling me that it is up to the member to make sure direct debits work and that I won’t be getting a 5.00 credit. This is in reply to my email of 01 Dec, not any of the subsequent ones, so I’m not sure how seriously to take it.

Update 2007-12-13 Email 47 – Customer Support send me the “apology for delay” email for the second time.

Update 2007-03-21: Sent a few more emails in January and a couple more in February and kind of gave up on the whole thing. They just gave me five pounds credit (not refund) this morning.