【问题标题】:Haskell: Abstracting a Genetic AlgorithmHaskell:抽象遗传算法
【发布时间】:2011-02-15 22:28:17
【问题描述】:

我是 Haskell 编程领域的新手,我正在尝试一种简单的遗传算法来寻找旅行商问题的良好解决方案。我将解决方案表示为整数的排列,所以我有这种类型的同义词

type Genome = [Int]

算法本身是一组对解进行操作的函数:

mutation :: Genome -> Genome
selectParents :: [Genome] -> [Genome] -> [Genome]
crossover :: Genome -> Genome -> (Genome, Genome)
selectSurvivors :: [Genome] -> [Genome] -> [Genome]

我不确定我的代码有多少与我的问题相关,所以请询问是否需要更多详细信息。可能值得一提的是,上面的类型签名实际上是简化的,我实际上是使用 State monad 来携带 StdGen 所以所有这些函数实际上都返回有状态的计算。

有几件事情我想用这个做,但我无法完全理解。我想让为解决方案选择不同的表示形式成为可能,在我看来,这将是使用类型类的自然场所,因此 Genome 将是类型类,[Int] 是这个的特定实例Genome。

现在,我希望能够对实现进行试验,并且希望能够在其他项目中使用该代码。使用这样的类型类需要我创建的每个新算法都需要我创建另一个 Genome 实例,这是创建库的好方法吗?

一个额外的问题,只是一直困扰我的一件事,有没有办法为函数创建类似类型同义词的东西,这样如果我正在编写一个以函数作为参数的函数,我可以编写同义词而不是函数的整个类型签名,即这样的东西可以工作。

type someFunc = [Int] -> [Int] -> Int
someOtherFunc :: someFunc -> [Int] -> Int

是的,希望这是对问题的足够清晰的解释,感觉就像我错过了非常明显的答案,但它并没有跳出来。干杯

【问题讨论】:

  • 基因组实例需要定义哪些功能? mutation、selectParents 等?或者是否有一组更小(更简单)的函数,您可以根据这些函数来定义这些函数?
  • 我可能错了,但我认为这些功能尽可能简单。也许我只是想让它比可能的更通用。
  • 这样的声音会在邮件列表中引发很好的讨论。见Haskell mailing lists
  • 在类型别名问题上,您提供的代码应该可以正常工作。不是吗?
  • @sclv,类型别名必须大写。除此之外,它应该可以工作。

标签: haskell evolutionary-algorithm


【解决方案1】:

不幸的是,理想的解决方案通常取决于您的问题领域。 This blog post 谈论类型类方法和按位方法。如果您想要灵活性,我个人认为混合方法是最好的。如果有好的按位映射,你可以定义它,并从中派生出实现,否则你可以手动实现交叉和变异。

ja 的方法实际上是行不通的。你的一些基因组函数需要随机输入,你可以通过在状态单子中运行随机数生成器like this thread

class Genome a where
    fitness :: a -> Int
    breed :: (RandomGen g, MonadState g m) => a -> a -> m a
    mutate :: (RandomGen g, MonadState g m) => a -> m a

那么你就有了对基因组集进行操作的通用函数,而不管实现如何。

selectParents :: (Genome a, RandomGen g, MonadState g m) => [a] -> m [a]
selectSurvivors :: (Genome a, RandomGen g, MonadState g m) => [a] -> m [a]

如果你确实有一个好的位映射,你可以在 BitArrays 上定义固定函数(注意每个都必须将适应度函数作为参数)

breed :: (RandomGen g, MonadState g m) => BitArray -> BitArray -> m BitArray
mutate :: (RandomGen g, MonadState g m) => BitArray -> m BitArray
selectParents :: (RandomGen g, MonadState g m) => (BitArray -> Int) -> [BitArray] -> m [BitArray]
selectSurvivors :: (RandomGen g, MonadState g m) => (BitArray -> Int) -> [BitArray] -> m [BitArray]

【讨论】:

  • 使用同名包中的MonadRandom类。
【解决方案2】:

是的,使用类型类来表示基因组是一个不错的方法。像这样的:

类基因组在哪里 突变 :: a -> a 选择父母 :: [a] -> [a] -> [a] 交叉 :: a -> a -> (a, a) 选择幸存者 :: [a] -> [a] -> [a] 实例基因组 [a] 其中 突变 l = l 选择父母 l1 l2 = l1 交叉 g1 g2 = (g1,g2) 选择幸存者 l1 l2 = l1 数据树 a = 叶 a |分支[树一] 实例基因组(树 a)其中 突变 t = t 选择父母 l1 l2 = l1 交叉 g1 g2 = (g1,g2) 选择幸存者 l1 l2 = l1

至于为每个算法实例化一个新数据类型,您可以在库中包含一些实例,但实例化新实例没有问题 - 这就是重点!

【讨论】:

    猜你喜欢
    • 2011-01-11
    • 2012-07-07
    • 2011-07-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-05
    • 2016-06-23
    相关资源
    最近更新 更多