重构F#函数以利用前向管道运算符

4
type Range = int * int
type Domain = Range array

type Gene = int
type Individual = Gene array
type Population = Individual array

let genPop (domain:Domain) popSize =
  let genInd (domain:Domain) : Individual =
    let genGene (range:Range) = genNum (fst range) (snd range)
    Array.map genGene domain
  Array.init popSize (fun _ -> genInd domain)

所以,一个Population只是由Individuals数组组成。每个Individual都由Gene数组组成,而Gene仅是整数的别名。genNum将为我们生成随机整数。
我对我的genPop实现不是特别满意。虽然它正常工作并符合预期,但我想尝试一种使用前向管道运算符|>的实现方式,而不是使用子函数。
如何继续进行?理想情况下,我们可以从popSize开始,将其转换为一个Population,该Population具有作为其成员的Individuals,这些Individuals由Genes组成。问题在于,我们通常需要反过来做。我们首先需要创建基因,然后才能创建个体,最后才能拥有人口!
你会如何实现这个功能(除了我所做的方式之外)?也许还有其他的方法,目前对我来说还不明显?
3个回答

5

使用模式匹配替换fstsnd

let genGene (x, y) = genNum x y

您的整个函数可以变为:

let genPop domain popSize =
  Array.init popSize (fun _ -> Array.map (fun (x, y) -> genNum x y) domain)

或者:

let genPop domain popSize =
  [|for _ in 1..popSize ->
      [|for x, y in domain ->
          genNum x y|]|]

1

该函数可以通过使用管道进行简化:

let uncurry f = fun(a,b) -> f a b //Helper function

let genPop (domain:Domain) popSize : Population  =
  (fun _ -> domain)
  |> Array.init popSize 
  |> Array.map ((uncurry genNum) |> Array.map)

1

这是我的(第二次)尝试:

let genPop (domain : Domain) popSize : Individual [] =
    (fun _ ->
    domain
    |> Array.map (fun (a, b) -> genNum a b))
    |> Array.init popSize
    |> Array.map (Array.copy)

那段代码与 OP 中显示的不同,它会使所有个体都相等。 - devoured elysium
是的,我假设genNum是一个完全功能的函数。我应该注意到gen是generate的缩写 :) - Ramon Snir

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接