Причина сообщения об ошибке заключается в том, что ваша реализация 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
Чтобы дать некоторые общие подсказки, я бы, вероятно, не использовал Unchecked.defaultof<'GeneType>
Вместо этого вы должны использовать тип option
, когда имеете дело с ситуацией, когда значение может отсутствовать. Тип результата GeneNotTaken
будет тогда option<'GeneType>
. Вместо match
вы можете написать:
trial |> Option.map (fun actualTrial ->
taken.Add(actualTrial)
actualTrial )
Кроме того, ваш код использует много мутаций, что может быть не лучшим решением при написании функционального кода на F #. Однако, если вы только изучаете F #, то, вероятно, неплохо бы начать с переписывания некоторого кода на C # в F #. По мере того, как вы узнаете больше, вы должны искать способы избежать мутации, потому что это сделает ваш код F # более идиоматичным (и будет еще интереснее писать его!)