gpt4 book ai didi

haskell - Haskell 类型类的重新设计

转载 作者:行者123 更新时间:2023-12-02 10:18:41 24 4
gpt4 key购买 nike

在获得一些帮助后,了解了我尝试编译代码的问题,在这个问题(Trouble understanding GHC complaint about ambiguity)中,Will 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

我正在尝试在 Haskell 中创建一个可扩展的进化算法,它应该支持不同的基因组表型。例如,一个Genome可能是一个位数组,另一个可能是一个整数列表,而Phentypes也将不同于代表http://en.wikipedia.org/wiki/Colonel_Blotto中部队移动的 double 列表,或者它可以代表一个 ANN。

由于Phenotype是从Genome发展而来的,所以所使用的方法必须是完全可以互换的,并且一个Genome类应该能够支持多个表型通过提供不同的开发方法(这可以在代码中静态完成,不必在运行时动态完成)。

在大多数情况下,使用这些类型类的代码应该完全不知道所使用的特定类型,这就是我提出上述问题的原因。

我想要适应这些类型类的一些代码是:

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

我知道必须更改此代码并且必须添加新的约束,但我想展示一些我想到的使用类型类的代码。例如,上面的完整世代替换不需要了解有关底层基因组的任何信息即可正常运行;它只需要知道表型可以产生产生它的基因组,这样它就可以将它们一起繁殖并创造新的 child 。 fullGenerational 的代码应尽可能通用,以便一旦设计了新的Phenotype 或创建了更好的Genome,就不需要待更改。

如何更改上面的类型类,以避免我曾经/正在遇到的类型类模糊性问题,同时保留我在通用 EA 代码中想要的属性(应该是可重用的)?

最佳答案

"it only needs to know that Phenotypes can produce the Genome which produced it "

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

{-# 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 implementation 基因组

关于haskell - Haskell 类型类的重新设计,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15766904/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com