2013-04-02 29 views
4

在获得一些帮助之后,理解我试图编译代码的问题,在这个问题中(Trouble understanding GHC complaint about ambiguity)Ness建议我重新设计我的类型类以避免我不完全满意的解决方案。Haskell类型类的重新设计

有问题的类型类是这些:

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 

我试图创建在Haskell一种可伸缩进化算法,应支持不同GenomesPhenotypes。例如,一个Genome可能是一个位阵列,另一个可能是一个整数列表,而且Phenotypes也可能不同,只是代表部队运动的双打列表http://en.wikipedia.org/wiki/Colonel_Blotto,或者它可以代表一个ANN。

由于PhenotypeGenome使用的必须是相当互换的方法开发的,一个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 

据我所知,这个代码将不得不改变,新的限制将被添加,但我想表现我想到的一些代码使用类型类。例如,上面的全代更换并不需要知道任何关于底层Genome的功能;它只需要知道Phenotypes可以生产Genome,它可以将它们一起繁殖并创建新的孩子。 fullGenerational的代码应尽可能一般,以便一旦设计了新的Phenotype或创建了更好的Genome,则不需要更改它。

上述类型类如何改变以避免我在类型类模糊性方面遇到的问题,同时保留了我在普通EA代码中的属性(应该是可重用的)?

+0

将类型转换为等效字典:参见[this](http://www.haskellforall.com/2012/05/scrap-your-type-classes.html)和[this](http:// lukepalmer.wordpress.com/2010/01/24/haskell-antipattern-existential-typeclass/)。 –

+0

@GabrielGonzalez嗯,我可能会误解,但这将如何帮助解决我模糊不清的问题?我明白,风格可能更清晰,但我不明白如何将我已有的内容转换为数据声明来解决问题。 – Nordmoen

+0

对不起,我误解了你含糊不清的含义。不理我。 –

回答

7

“它只需要知道的表型可以产生产生它的基因组”

这意味着表型确实出现两种类型的关系,另一个是基因组类型用于产生一个给定表型:

{-# 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 

这个编译。每种表型will have to provide exactly one implementationgenome

+0

这似乎是我正在寻找。这个答案中唯一缺少的是你在评论中提供的链接(http://www.haskell.org/haskellwiki/Functional_dependencies) – Nordmoen

+0

@Nordmoen btw我不记得使用的语言杂注的确切拼写这里,心脏;我只是试图将文件加载到GHCi中,它告诉我哪些选项丢失了。 –

+0

@Nordmoen BTW与Phenotype类定义中的Genome b'约束,两个函数的约束'Genome a'是多余的,可以删除。但它并没有受到伤害,也许还有其他的文件目的。 –