module Hamming
let distance (strand1: string) (strand2: string) : int option =
if strand1.Length <> strand2.Length
then None
else
[ for idx in 0 .. strand1.Length - 1 do
if strand1[idx] <> strand2[idx] then yield 1 else yield 0 ]
|> List.sum
|> Some
Error path
We start by checking if the strings have unequal lengths, and return None if so:
if strand1.Length <> strand2.Length
then None
Note that we're using string class' Length property, not a function like Seq.length.
Even though F# is a functional-first language, you'll use types (like the string class) defined in the .NET framework, which is an object-oriented framework.
Inevitably, you'll thus use objects that have methods and properties defined on them.
Don't worry about using methods and objects though, F# is a multi-paradigm language and embraces the interaction with object-oriented code (like the string class).
Happy path
In the happy path, we know that the strings have the same length so we can use the length (minus one) of the first string as the max of a range of indices to use to access each char of both strings and compare them:
for idx in 0 .. strand1.Length - 1 do
The entire for expression is surrounded by square brackets ([]) indicating that this is a List comprehension.
This gives you the power of returning intermediate results based on comparing each pair of chars (returning a 1 when they differ or a 0 if they don't) and then continuing the next pair until you reach the end:
if strand1[idx] <> strand2[idx] then yield 1 else yield 0
The yield keyword indicates that this concerns an intermediate result, this can also be used in C#.
The resulting list of 1's and 0's is then piped into a List.sum to get the hamming distance and finally the result is wrapped in a Some.
|> List.sum
|> Some