What general tips do you have for golfing in F#? I'm looking for ideas that can be applied to code golf problems in general that are at least somewhat specific to F# (e.g. "remove comments" is not an answer). Please post one tip per answer.
function instead of
match when possible; it'll save 6 characters for 1-character variables:
let f=function // ... (14 chars)
let f x=match x with // ... (20 chars)
It can also replace any pattern match to consistently save 1 character:
match a with| // ... (13 chars) a|>function| // ... (12 chars) (function| (* ... *))a // (12 chars)
Need to use a method on variable for which you haven't yet constrained the type? Just compare it against a literal of the type you want it to be then throw away the result to annotate that variable's type:
let f (x:string)=x.Length let f x=x="";x.Length
Use the prefix notation for infix operators when you can - it'll save you from having to define a function to use them.
For example, you can turn this:
In case you can't get around to using variables, use tuple deconstruction instead of multiple let expressions
let a,b ="",
let a="" let b=
Reading from stdin
F# core library defines an alias for
stdin. These allow you to read input.
// Signature: stdin<'T> : TextReader
The big advantage aside the fact that it's shorter than
Console is, you don't have to open System either
Iterating over string
string is basically a
char seq, this allows you to use
Seq.map directly with strings. It's also possible to use them in comprehensions
[for c in "" do]
Using reference cells is not always shorter as every read operation comes with an additional character to deref the cell.
It is possible to write the complete
match .. withinline
There is no need for white-space before and after non alphanumeric characters.
String.replicate 42" " if Seq.exists((<>)'@')s then if(Seq.exists((<>)'@')s)then
In case you need to left or right pad a string with spaces, you can use [s]printf[n] flags for that.
> sprintf "%20s" "Hello, World!";; val it : string = " Hello, World!"
Eta-conversion for functions
Consider a function to, say, sum a string with 3 for upper-case letters and 1 for all other characters. So:
let counter input = Seq.sumBy (fun x -> if Char.IsUpper x then 3 else 1) input
By eta-conversion this can be re-written as:
let counter = Seq.sumBy (fun x -> if Char.IsUpper x then 3 else 1)
and called in the same way as before:
counter "Hello world!" |> printfn "%i"
The function forward-composition operator
Now suppose our original challenge would be to sum a string with 3 for upper-case letters and 1 for lower-case letters, and all other characters are excluded.
We might write this as:
let counter input = Seq.filter Char.IsLetter input |> Seq.sumBy (fun x -> if Char.IsUpper x then 3 else 1)
We can use the forward-composition operator (
>>) to chain the two functions (
Seq.sumBy) together. With eta-conversion the function definition would become:
let counter = Seq.filter Char.IsLetter >> Seq.sumBy (fun x -> if Char.IsUpper x then 3 else 1)
Chris Smith did a great write-up on the
>> operator on his MSDN blog.
Seq is shorter than
is one char shorter...
Avoid parenthesis when using one parameter and on tuple
let f = [(0,1);(1,4)]|>Seq.map(fst) printfn "%A" f
can be written
let f = [0,1;1,4]|>Seq.map fst printfn "%A" f
.NET offers a lot of nice builtins. F# can use them, so dont forget them!
It can be helpful!
Use lambdas to save a byte. For example, this:
let f x=x*x
Can be expressed as this:
module keyword can be used to shorten module names when used repeatedly. For example:
Array.fold ... Seq.iter ... List.map ...
module A=Array A.fold ... module S=Seq S.iter ... module L=List L.map ...
This is more useful for longer programs where module methods are used repeatedly (and must be fully named each time because they have the
RequireQualifiedAccess modifier), and allows shaving a few chars off especially when it's more useful to use a regular CLR array (e.g., mutability) than an F#