Nor*_*oen 4 haskell typeclass evolutionary-algorithm
在得到一些帮助后,理解我试图编译代码的问题,在这个问题中(麻烦理解GHC关于模糊性的抱怨)Ness会建议我重新设计我的类型类以避免我不满意的解决方案.
有问题的类型是这些:
class (Eq a, Show a) => Genome a where
crossover :: (Fractional b) => b -> a -> a -> IO (a, a)
mutate :: (Fractional b) => b -> a -> IO a
develop :: (Phenotype b) => a -> b
class (Eq a, Show a) => Phenotype a where
--In case of Coevolution where each phenotype needs to be compared to every other in the population
fitness :: [a] -> a -> Int
genome :: (Genome b) => a -> b
Run Code Online (Sandbox Code Playgroud)
我正在尝试在Haskell中创建一个可扩展的进化算法,它应该支持不同的Genomes和Phenotypes.例如,一个Genome可以是一个位数组,另一个可以是一个整数列表,并且Phenotypes也可以从http://en.wikipedia.org/wiki/Colonel_Blotto中代表部队运动的双重列表中区分,或者它可以代表ANN.
由于a Phenotype是从所开发Genome的方法开发的,因此必须是可以互换的,并且一个Genome类应该能够Phenotypes通过提供不同的开发方法来支持多个(这可以在代码中静态完成,而不必在运行时动态完成).
在大多数情况下,使用这些类型类的代码应该幸福地不知道所使用的特定类型,这就是让我提出上述问题的原因.
我想要适应这些类型类的一些代码是:
-- |Full generational replacement selection protocol
fullGenerational :: (Phenotype b) =>
(Int -> [b] -> IO [(b, b)]) -> --Selection mechanism
Int -> --Elitism
Int -> --The number of children to create
Double -> --Crossover rate
Double -> --Mutation rate
[b] -> --Population to select from
IO [b] --The new population created
fullGenerational selection e amount cross mute pop = do
parents <- selection (amount - e) pop
next <- breed parents cross mute
return $ next ++ take e reverseSorted
where reverseSorted = reverse $ sortBy (fit pop) pop
breed :: (Phenotype b, Genome a) => [(b, b)] -> Double -> Double -> IO [b]
breed parents cross mute = do
children <- mapM (\ (dad, mom) -> crossover cross (genome dad) (genome mom)) parents
let ch1 = map fst children ++ map snd children
mutated <- mapM (mutate mute) ch1
return $ map develop mutated
Run Code Online (Sandbox Code Playgroud)
我知道必须更改此代码并且必须添加新的约束,但我想要使用类型类来显示我想到的一些代码.例如,上面的完整世代替换不需要知道关于底层Genome功能的任何信息; 它只需要知道Phenotypes可以产生Genome它产生它,以便它可以一起繁殖它们并创造新的孩子.代码fullGenerational应该尽可能通用,以便一旦Phenotype设计了new 或者Genome创建了更好的代码,就不需要更改它.
如何更改上面的类型类以避免我遇到类型类歧义的问题,同时在一般EA代码中保留我想要的属性(应该是可重用的)?
"它只需要知道表型可以产生产生它的基因组"
这意味着Phenotype实际上是两种类型的关系,另一种是用于产生给定表型的基因组类型:
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FunctionalDependencies #-}
import Data.List (sortBy)
class (Eq a, Show a) => Genome a where
crossover :: (Fractional b) => b -> a -> a -> IO (a, a)
mutate :: (Fractional b) => b -> a -> IO a
develop :: (Phenotype b a) => a -> b
class (Eq a, Show a, Genome b) => Phenotype a b | a -> b where
-- In case of Coevolution where each phenotype needs to be compared to
-- every other in the population
fitness :: [a] -> a -> Int
genome :: a -> b
breed :: (Phenotype b a, Genome a) => [(b, b)] -> Double -> Double -> IO [b]
breed parents cross mute = do
children <- mapM (\(dad, mom)-> crossover cross (genome dad) (genome mom))
parents
let ch1 = map fst children ++ map snd children
mutated <- mapM (mutate mute) ch1
return $ map develop mutated
-- |Full generational replacement selection protocol
fullGenerational :: (Phenotype b a, Genome a) =>
(Int -> [b] -> IO [(b, b)]) -> --Selection mechanism
Int -> --Elitism
Int -> --The number of children to create
Double -> --Crossover rate
Double -> --Mutation rate
[b] -> --Population to select from
IO [b] --The new population created
fullGenerational selection e amount cross mute pop = do
parents <- selection (amount - e) pop
next <- breed parents cross mute
return $ next ++ take e reverseSorted
where reverseSorted = reverse $ sortBy (fit pop) pop
fit pop a b = LT -- dummy function
Run Code Online (Sandbox Code Playgroud)
这编译.每个表型将不得不提供一个准确实施的genome.