gpt4 book ai didi

generics - F# 泛型类型问题

转载 作者:行者123 更新时间:2023-12-02 22:00:42 25 4
gpt4 key购买 nike

我正在尝试将一些 C# 代码转换为 F#,但遇到了一个小问题。这是我已有的 F# 代码:

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

一切都很顺利,直到我开始使用“未采用基因”方法。下面是该方法的 C# 代码(我还需要返回默认类型的帮助,但还没有做到这一点):

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);
}

我看到的编译器错误包括:

"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."

"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'."

您可能会认为第一个错误是非常清楚的,除非您可以看到我在此之前没有使用 GeneNotTaken 成员,这就是为什么我不知道问题是什么。

我的问题的第二部分是如何在方法末尾添加 return default('GeneType) 。

如果您对改进我的代码还有其他建议,请随时分享。

最佳答案

出现错误消息的原因是您执行 GeneTaken实际上并没有返回 trial值(value)。问题是 F# 没有命令式 return陈述。

在 F# 中,if .. then ..被视为计算并给出一些结果的表达式。例如,您可以写 let a = if test then 10 else 12 。当您省略 else 分支时,语句的主体必须是返回 unit 的命令式操作。 (表示无返回值的类型)。你不能写let a = if test then 42 - 如果test = false,结果的值是多少?

您可以通过使用递归循环编写方法来修复它 - 然后您就有一个实际上返回 trial 的方法。因此 F# 类型检查器不会感到困惑:

member this.GeneNotTaken
(source:Chromosome<'GeneType>, taken:IList<'GeneType>) : 'GeneType =
let geneLength = source.Size
let rec loop i =
if i >= geneLength then Unchecked.defaultof<'GeneType> // Return default
let trial = source.GetGene(i)
if (not (taken.Contains(trial))) then
// Gene was found, process it & return it
taken.Add(trial)
trial
else
// Continue looping
loop (i + 1)
loop 0

使用 Seq.tryPick 的替代(可能更好)实现功能:

member this.GeneNotTaken
(source:Chromosome<'GeneType>, taken:IList<'GeneType>) : 'GeneType =
let geneLength = source.Size
// Find gene that matches the given condition
// returns None if none exists or Some(trial) if it was found
let trial = [ 0 .. geneLength - 1 ] |> Seq.tryPick (fun i ->
let trial = source.GetGene(i)
if (not (taken.Contains(trial))) then Some(trial) else None)
match trial with
| Some(trial) ->
// Something was found
taken.Add(trial)
trial
| _ ->
Unchecked.defaultof<'GeneType> // Return default

为了给出一些一般提示,我可能不会使用 Unchecked.defaultof<'GeneType>相反,您应该使用 option当您处理可能缺少值的情况时键入。结果类型GeneNotTaken那么将是option<'GeneType> 。而不是match你可以写:

  trial |> Option.map (fun actualTrial ->
taken.Add(actualTrial)
actualTrial )

此外,您的代码使用了大量突变,这在 F# 中编写函数代码时可能不是最好的做法。但是,如果您刚刚学习 F#,那么最好先将一些 C# 代码重写为 F#。随着您了解更多,您应该寻找避免突变的方法,因为这将使您的 F# 代码更加惯用(并且编写它也会更有趣!)

关于generics - F# 泛型类型问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5286119/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com