I’m trying to convert some C# code to F# and have encountered a slight problem. Here is the F# code that I have already:
open System
open System.Collections
open System.Collections.Generic
type Chromosome<'GeneType>() =
let mutable cost = 0
let mutable (genes : 'GeneType[]) = Array.zeroCreate<'GeneType> 0
let mutable (geneticAlgorithm : GeneticAlgorithm<'GeneType>) = new GeneticAlgorithm<'GeneType>()
/// The genetic algorithm that this chromosome belongs to.
member this.GA
with get() = geneticAlgorithm
and set(value) = geneticAlgorithm <- value
/// The genes for this chromosome.
member this.Genes
with get() = genes
and set(value) = genes <- value
/// The cost for this chromosome.
member this.Cost
with get() = cost
and set(value) = cost <- value
/// Get the size of the gene array.
member this.Size = genes.Length
/// Get the specified gene.
member this.GetGene(gene:int) =
genes.[gene]
member this.GeneNotTaken(source:Chromosome<'GeneType>, taken:IList<'GeneType>) =
let geneLength = source.Size
for i in 0 .. geneLength do
let trial = source.GetGene(i)
if(not (taken.Contains(trial))) then
taken.Add(trial)
trial
Everything was going fine until I started on the Gene not taken method. Here is the C# code for that method (I also need help with returning the default type as well, but just didn’t make it that far yet):
private GENE_TYPE GetNotTaken(Chromosome<GENE_TYPE> source,
IList<GENE_TYPE> taken)
{
int geneLength = source.Size;
for (int i = 0; i < geneLength; i++)
{
GENE_TYPE trial = source.GetGene(i);
if (!taken.Contains(trial))
{
taken.Add(trial);
return trial;
}
}
return default(GENE_TYPE);
}
Compiler errors I’m seeing include:
“The generic member ‘GeneNotTaken’ has been used at a non-uniform instantiation prior to this program point. Consider reordering the members so this member occurs first. Alternatively, specify the full type of the member explicitly, including argument types, return type and any additional generic parameters and constraints.”
and
“This code is less generic than required by its annotations because the explicit type variable ‘GeneType’ could not be generalized. It was constrained to be ‘unit’.”
You would think the first error would be crystal clear, except as you can see I didn’t use the GeneNotTaken member prior to that point, which is why I don’t know what the problem is.
The second part of my question is how to add the return default(‘GeneType) at the end of the method.
If you have some other suggestions for improvement of my code in general, please feel free to share them.
The reason for the error message is that your implementation of
GeneTakenis not actually returning thetrialvalue. The problem is that F# doesn’t have imperativereturnstatement.In F#,
if .. then ..is treated as an expression that evaluates and gives some result. For example, you can writelet a = if test then 10 else 12. When you omit the else branch, the body of the statement must be some imperative action that returnsunit(a type representing no return value). You cannot writelet a = if test then 42– what would be the value of the result iftest = false?You can fix it by writing the method using a recursive looping – then you have a method that actually returns
trialand so the F# type checker isn’t confused:An alternative (maybe nicer) implementation using
Seq.tryPickfunction:To give some general hints, I probably wouldn’t use
Unchecked.defaultof<'GeneType>Instead, you should useoptiontype when you’re dealing with situation where a value may be missing. The result type ofGeneNotTakenwould then beoption<'GeneType>. Instead ofmatchyou could write:Also, your code uses a lot of mutation, which may not be the best thing to do when writing functional code in F#. However, if you’re just learning F# then it’s probably good to start by rewriting some C# code into F#. As you learn more, you should look for ways to avoid mutation, because it will make your F# code more idiomatic (and it will be more fun to write it too!)