【问题标题】:Call monadic function inside transformer stack在转换器堆栈中调用一元函数
【发布时间】:2014-05-02 00:16:34
【问题描述】:

我在 Monad Transformers 中第一次尝试。为我的班级所说的“设施位置”问题编写了一个简单的遗传算法。算法不是那么重要。

我一般遵循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 函数只是将两个向量拼接在一起:

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 来固定我的圆形计数器。这比在 step 中添加参数要快。有没有更有效的方法来解决这个问题?

【问题讨论】:

    标签: haskell monads monad-transformers


    【解决方案1】:

    您的offspring 函数返回Rand 计算。然而,Rand 只是一个特定的MonadRandom 实例(是RandT 超过Identity),而不是你的FacilityApp monad。您应该将Rand 更改为FacilityApp,或者,如果您只使用MonadRandom 函数,请将类型推广到任何MonadRandom

    offspring :: (MonadRandom m) => CustomerService -> CustomerService
              -> m (CustomerService, CustomerService)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2010-09-15
      • 2019-11-22
      • 1970-01-01
      • 2014-11-13
      • 2014-08-30
      • 2019-11-25
      • 2017-07-18
      相关资源
      最近更新 更多