2011-03-12 6 views
2

일부 C# 코드를 F #으로 변환하려고하는데 약간의 문제가 발생했습니다. 다음은 이미 가지고있는 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 

Gene not taken 메서드를 시작하기 전까지는 모든 것이 잘 진행되고있었습니다. 제가 보는

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

컴파일러 오류는 다음과 같습니다 : 다음은 그 방법에 대한 C# 코드 (나는 또한뿐만 아니라 기본 유형을 반환 도움이 필요하지만, 그냥 지금까지 아직하지 않았다)이다

"이 프로그램 포인트 이전에 일률적 인 인스턴스 생성시 일반 멤버 'GeneNotTaken'이 사용되었습니다.이 멤버가 먼저 발생하도록 멤버의 순서를 변경하거나 인수 유형을 포함하여 멤버의 전체 유형을 명시 적으로 지정하십시오 , 반환 유형 및 추가 일반 매개 변수 및 제약 조건이 포함됩니다. "

는 "이 코드는 명시 적 유형 변수 'GeneType가'일반화 할 수 없기 때문에 그 주석에 의해 요구되는 것보다 덜 일반적인이다. 그것은 '단위'로 제한했다."

당신은 내가 이전에 내가 문제가 무엇인지 모르는 이유는 그 시점에 GeneNotTaken 멤버를 사용하지 않은 볼 수있는 경우를 제외하고 첫 번째 오류는, 맑은있을 거라고 생각합니다.

내 질문의 두 번째 부분은 메서드의 끝에 반환 기본값 ('GeneType)을 추가하는 방법입니다.

내 코드 개선을위한 다른 제안 사항이 있으면 언제든지 공유하십시오.

답변

7

오류 메시지의 원인은 GeneTaken의 구현이 실제로 trial 값을 반환하지 않기 때문입니다. 문제는 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 

은 몇 가지 일반적인 힌트를 제공하기 위해, 나는 아마 당신은 당신이 상황을 다루고 option 형식을 사용한다, 대신 Unchecked.defaultof<'GeneType>를 사용하지 것이다 값이 누락 될 수 있습니다. 결과 유형 GeneNotTakenoption<'GeneType>이됩니다.대신 match 당신은 쓸 수 :

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

또한, 코드는 F #으로 기능 코드를 작성할 때 할 수있는 최선의 일은하지 않을 수 있습니다 돌연변이를 많이 사용합니다. 그러나 F #을 배우면 F #으로 일부 C# 코드를 다시 작성하는 것이 좋습니다. F # 코드를 좀 더 관용적으로 만들 것이므로 돌연변이를 피하는 방법을 찾아야합니다 (그리고 더 재미있을 것입니다!)

+0

Tomas! – Beaker

+2

오타가 눈치 챘을 것입니다. 그러나 마지막 루프 0은 내가 생각하는 대답의 첫 부분에서 오프사이드입니다. – FinnNk

+0

@FinnNk : 지적 해 주셔서 감사합니다. 나는 대답을 고쳤다. –