在相同数据结构上运行的类似功能

时间:2015-12-18 17:24:54

标签: haskell code-duplication

我有以下格式的数据类型:

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的星期一旅行交换。

对于大多数突变,我需要以下步骤:

  1. 我需要随机性来确定要变异的Trip(s)。
  2. 改变Trips
  3. 返回更新的解决方案
  4. 显然(2.)对于每个突变功能都是唯一的。但是(1.)和(3.)非常相似。

    实现这一点的好方法是什么,而不必为每个突变函数复制步骤1(和3)?

1 个答案:

答案 0 :(得分:3)

概念:高阶函数

高阶函数是一个将另一个函数作为输入的函数。在没有意识到的情况下,您可能已经使用了几个高阶函数(例如mapfoldl)。

只需使用高阶功能,即签名:

mutateGeneric :: (Trip -> IO Trip) -> Solution -> IO Solution

所以这里第一个参数是一个改变行程的函数,你的mutateGeneric函数本身会生成随机数,根据函数执行修改,然后返回解。如果您不执行IO(例如因为生成了随机数),您只需使用:

mutateGeneric :: (Trip -> Trip) -> Solution -> Solution

实施例

假设您首先在int0(包括)之间生成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函数中执行此操作。