I think there’s a time for all of us when we sat down to write a piece of code and it worked perfectly first time, and we thought to ourselves that perhaps we might just make developers of ourselves yet – shortly before we found an edge case that wasn’t covered, or irreparably broke everything with our overconfidence.
I’ve recently been going through Project Euler problems again – having solved a great many of them in C# – and solving them in F#. And it’s been amazing. That feeling of things working first time has become more commonplace than it has any right to be, particularly in a language that I’m (relatively) unfamiliar with and when I’m writing code with no IDE niceties (LinqPad); and since I’m fairly certain that I haven’t become insanely competent at overnight, I can’t help but feel that it can only be attributed to the language and paradigm itself.
If I wasn’t before, I’m certainly feeling the love for F# now.
Problem 13 is incredibly simple if you have an arbitrary-sized integer type, and while I could easily use
Math.bigint, I thought it might be a nice exercise to create my own. Now, the code below may not be the prettiest in the world, and it certainly isn’t the most efficient, but for something that I knocked together in a few minutes in my spare time without taking too much care over… it worked first time! (Well… almost anyway… the first time around I forgot the case where the digits had all been dealt with but
carried wasn’t zero.) Hopefully that doesn’t undermine my point too much, because I’ve truly been impressed by how much I feel helped rather than hindered by the language.
type BigNum (digits: int list) = // digits: list of decimal digits smallest-biggest static let carryDigits digits = let rec carryDigits digits processed carried = let getDigitAndCarry next = next % 10, next / 10 match digits with |  -> match carried with | 0 -> processed // all done and nothing more to carry | _ -> // digits all done, but still carrying left let digit, carriedNext = getDigitAndCarry carried carryDigits digits (digit :: processed) carriedNext | _ -> // keep going...! let next = (List.head digits) + carried let digit, carriedNext = getDigitAndCarry next carryDigits (List.tail digits) (digit :: processed) carriedNext carryDigits digits  0 |> List.rev member this.digits = carryDigits digits static member Create (s: string) = let numStringToList (s: string) = s |> Seq.map (string >> Int32.Parse) |> List.ofSeq |> List.rev let digits = numStringToList s BigNum(digits) static member (+) (a: BigNum, b: BigNum) = let matchLengths list1 list2 = let extend list toLength = let lengthToAdd = max 0 (toLength - List.length list) let zeroes = [for i in 1..lengthToAdd -> 0] list @ zeroes let list1' = extend a.digits (List.length list2) let list2' = extend b.digits (List.length list1) list1', list2' let resultDigits = matchLengths a.digits b.digits ||> List.zip |> List.map (fun (a,b) -> a + b) |> carryDigits BigNum(resultDigits) override this.ToString() = List.fold (fun acc x -> string(x) + acc) "" digits