addToLeftPlayerPos的正确实现是什么

问题描述 投票:1回答:1

我试图跟随this paper进行功能反应式编程,但我仍然坚持第4.2节中的第二个例子。

我得到了第一个启动并运行阅读器变换器的示例:

module Main where

import FRP.BearRiver    
import Control.Monad.Trans.MSF.Reader

type Game = Ball
type Ball = Int

type GameEnv = ReaderT GameSettings

data GameSettings
    = GameSettings
      { leftPlayerPos  :: Int
      , rightPlayerPos :: Int
      }

ballToRight :: Monad m => MSF (GameEnv m) () Ball
ballToRight =
    count >>> arrM addToLeftPlayerPos
    where
      addToLeftPlayerPos =
          (\n -> (n +) <$> asks leftPlayerPos)

hitRight :: Monad m => MSF (GameEnv m) Ball Bool
hitRight = arrM (\i -> (i >=) <$> asks rightPlayerPos)

但是下一步我正在努力。我无法弄清楚如何正确引入编写器转换器,因为我甚至无法编译:

module Main where

import FRP.BearRiver
import Control.Monad
import Control.Monad.Trans.MSF.Reader
import Control.Monad.Trans.MSF.Writer

type Game = Ball
type Ball = Int

type GameEnv m =
    WriterT [String] (ReaderT GameSettings m)

data GameSettings
    = GameSettings
      { leftPlayerPos  :: Int
      , rightPlayerPos :: Int
      }

ballToRight :: Monad m => MSF (GameEnv m) () Ball
ballToRight =
    count >>> arrM addLeftPlayerPos >>> arrM checkHitR
    where
      addLeftPlayerPos =
          (\n -> (n +) <$> asks leftPlayerPos)
      checkHitR n = do
          rp <- asks rightPlayerPos
when (rp > n) $ tell ["Ball is at " ++ (show n)]

实际上函数调用addLeftPlayerPos的行是有问题的,因为函数arrM addLeftPlayerPos没有在论文中给出,我的版本似乎缺少WriterT类型签名作为别名type GameEnv m ...建议

什么可能正确实施addLeftPlayerPos功能?

编辑:编译器错误是:

 Expected type: MSF (GameEnv m) () Ball
    Actual type: MSF (ReaderT GameSettings m1) () () 
• In the expression: 
    count >>> arrM addToLeftPlayerPos >>> arrM checkHitR 
haskell monads frp reader writer
1个回答
2
投票

Some phrasing

当你有一个变压器堆栈时,你必须“提升”你的操作来运行内部monad函数。例如:

type MyMonad a = Transformer1 (Transformer2 IO) a

这里的堆栈是IO的Transformer2的Transformer1。 “外部”monad是Transformer1,它将Transformer2与IO的内部(或底部,底部)monad包装在一起。在你的情况下,堆栈实际上是一个不知名的monad m读者的作家,一切都很好。

现在,如果我们想要在函数qazxsw poi中运行qazxsw poi,我们必须f :: Transformer2 IO a。同样,如果我们有g :: MyMonad并且我们希望从lift f内部运行那么我们可以getLine :: IO String

Lifting

如果您导入g :: Transformer1 (Transformer2 IO) a,您可以解除ReaderT操作。例如lift (lift getLine)而不仅仅是Control.Monad.Trans.Class

这确实有很大帮助。您评论的错误可能是由于在lift (asks ...)中使用asks ...

One More Type Error

完成提升后我们有错误:

asks

这是因为你的checkHitR没有返回值frosch.hs:23:5: error: • Couldn't match type ‘()’ with ‘Int’ Expected type: MSF (GameEnv m) () Ball Actual type: MSF (WriterT [[Char]] (ReaderT GameSettings m)) () () (我认为应该这样)。修复该问题为我们提供了以下最终代码:

checkHitR
© www.soinside.com 2019 - 2024. All rights reserved.