我在Monad变形金刚的第一次破解。为我的班级称之为“设施位置”的问题写了一个简单的遗传算法。算法并不那么重要。
我通常遵循本章Real World Haskell中解释的格式。
我的变压器堆栈看起来像这样
newtype FacilityApp a = MyA {
runA :: RandT StdGen ( ReaderT Environment ( StateT (Population, Int) IO)) a
} deriving (Monad, MonadIO, MonadReader Environment, MonadState (Population,Int), MonadRandom)
runFacility :: FacilityApp a -> Input -> StdGen -> IO a
runFacility k input g =
let env = mkEnv input defParms
(pop, g') = runRand (genInitialPopulation env) g
state = (pop, numRounds defParms)
ra = runA k
rr = runReaderT rrand env
rs = evalStateT rr state
rrand = evalRandT ra g'
in rs
后来在我的代码中,我定义了我的主要“步骤”动作,用于运行一轮交配和幸存。在我的步骤中,我可以轻松生成随机数并使用它。但是,我想将特定函数的随机性从步骤操作移到该函数中。不幸的是,我遇到类型错误,并且需要一些学校教育,为什么这不起作用,以及如何使这项工作。
你可能并不真的需要这个,但我的配偶功能只是将两个向量拼接在一起:
mate :: CustomerService -> CustomerService -> Int -> CustomerService
mate a b split = (fst $ V.splitAt split a) V.++ (snd $ V.splitAt split b)
所以,这有效:
offspring' :: CustomerService -> CustomerService -> Int -> (CustomerService, CustomerService)
offspring' a b split = (mate a b split, mate b a split)
step :: FacilityApp [CustomerService]
step = do
(pop, n) <- get
env <- ask
let e = (warehouses env, customers env)
let sorted@(p1:p2:_) = sortBy (sortByCost e) $ filter (validSolution e) pop
let (_:_:rest) = reverse sorted
-- these next two lines are of my concern
split <- getRandomR (1, V.length p1)
let (c1,c2) = offspring' p1 p2 split
-- eventually put the new children in the state and step again
put (c1:c2:rest, (n-1))
if n > 0 then step else return pop
但我真的宁愿定义后代:
offspring :: (RandomGen g) => CustomerService -> CustomerService -> Rand g (CustomerService, CustomerService)
offspring a b = do
split <- getRandomR (1, V.length a)
return (mate a b split, mate b a split)
然而,当我尝试使用类似
之类的步骤调用此函数时(c1,c2) <- offspring p1 p2
编译器对我大吼大叫说Rand类型与预期类型FacilityApp不匹配...我觉得这对我有意义,但我不知道如何让这对我有用。
我想也许这需要某种类型的提升和返回?但我无法弄明白。有人可以告诉我这个问题吗?
作为一个附带问题,请注意我正在使用StateT来举行我的圆形计数器。这比向步骤添加参数要快。是否有更有效的方法来处理这个问题?
答案 0 :(得分:3)
您的offspring
函数返回Rand
次计算。但是,Rand
只是一个特定的MonadRandom
个实例(RandT
超过Identity
),而不是您的FacilityApp
monad。您应该将Rand
更改为FacilityApp
,或者,假设您只使用MonadRandom
个功能,请将类型概括为任何MonadRandom
:
offspring :: (MonadRandom m) => CustomerService -> CustomerService
-> m (CustomerService, CustomerService)