我有以下格式的数据类型:
type Orders = [Int]
data Score = Score Cost Penalty Penalty
type Trip = (Int, Cost, Orders)
type Trips = [Trip]
type DaySolution = (Trips, Trips)
data Solution = Solution { score :: Score,
skippedOrders :: Orders,
monday :: DaySolution,
tuesday :: DaySolution,
wednesday :: DaySolution,
thursday :: DaySolution,
friday :: DaySolution
} deriving(Show)
我的主要'数据类型是解决方案。现在我想实现一些遗传/进化算法。
这意味着我必须改变Solution
。我的大多数突变都需要针对个体trip
进行操作。
例如,反转trip
的元素。或者周二和星期一的星期一旅行交换。或者甚至将解决方案1的星期一旅行与解决方案2的星期一旅行交换。
对于大多数突变,我需要以下步骤:
Trip
(s)。Trips
显然(2.)对于每个突变功能都是唯一的。但是(1.)和(3.)非常相似。
实现这一点的好方法是什么,而不必为每个突变函数复制步骤1(和3)?
答案 0 :(得分:3)
高阶函数是一个将另一个函数作为输入的函数。在没有意识到的情况下,您可能已经使用了几个高阶函数(例如map
和foldl
)。
只需使用高阶功能,即签名:
mutateGeneric :: (Trip -> IO Trip) -> Solution -> IO Solution
所以这里第一个参数是一个改变行程的函数,你的mutateGeneric
函数本身会生成随机数,根据函数执行修改,然后返回解。如果您不执行IO
(例如因为生成了随机数),您只需使用:
mutateGeneric :: (Trip -> Trip) -> Solution -> Solution
假设您首先在int
和0
(包括)之间生成4
以确定当天,然后您改变当天的两次旅行,最后返回变异的解决方案。
首先,我们将定义一些实用方法:
getDay :: Int -> Solution -> DaySolution
getDay 0 = monday
getDay 1 = tuesday
getDay 2 = wednesday
getDay 3 = thursday
getDay 4 = friday
setDay :: Int -> Solution -> DaySolution -> Solution
setDay 0 s d = s { monday = d }
setDay 1 s d = s { tuesday = d }
setDay 2 s d = s { wednesday = d }
setDay 3 s d = s { thursday = d }
setDay 4 s d = s { friday = d }
然后突变看起来像:
mutateGeneric modifier solution = do
di <- randomIO :: IO Int
tam <- modifier ta
tbm <- modifier tb
return $ setDay day solution (tam,tbm)
where day = mod day 5
(ta,tb) = getDay day solution
现在修饰符可以例如将第一个与第二个Trips
项交换:
swapModifier :: Trips -> IO Trips
swapModifier (a:b:s) = return (b:a:s)
swapModifier x = return x
然后最后你可以说你修改的heurstic是:
heuristic1 :: Solution -> IO Solution
heuristic1 = mutateGeneric swapModifier
关键是你可以简单地构建另一个修饰符,如swapModifier
,并将其与mutateGeneric
结合起来。当然上面的例子很简单。此外,您可能需要更新分数和处罚。您可以在mutateGeneric
函数中执行此操作。