addToLeftPlayerPos 的正确实现是什么
What is the correct implementation of addToLeftPlayerPos
我正在尝试按照 this paper 进行函数式响应式编程,但我仍然停留在第 4.2 节中的第二个示例上。
我得到了第一个例子 reader 变压器和 运行:
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
一些措辞
当你有一个转换器堆栈时,你必须 "lift" 你的操作到 运行 内部 monad 函数。例如:
type MyMonad a = Transformer1 (Transformer2 IO) a
这里的堆栈是IO的Transformer2的Transformer1。 "outer" monad 是 Transformer1,它用 IO 的最内层(或基础,底部)monad 包装 Transformer2。在您的情况下,堆栈实际上是某个未知 monad m
的 Reader 的 Writer,一切都很好。
现在,如果我们想从函数 g :: MyMonad
中 运行 f :: Transformer2 IO a
,我们必须 lift f
。同样,如果我们有 getLine :: IO String
并且我们希望 运行 从 g :: Transformer1 (Transformer2 IO) a
中得到它,那么我们可以 lift (lift getLine)
.
提升
如果导入 Control.Monad.Trans.Class
,则可以提升 ReaderT 操作。例如 lift (asks ...)
而不是 asks ...
.
这确实很有帮助。您评论的错误可能是由于在 checkHitR
.
中使用了 asks
还有一个类型错误
完成提升后出现错误:
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
没有 return 值 rp
(我认为它应该)。解决这个问题给了我们最终的代码:
module Main where
import FRP.BearRiver
import Control.Monad.Trans.Class
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 +) <$> lift (asks leftPlayerPos))
checkHitR n = do
rp <- lift (asks rightPlayerPos)
when (rp > n) $ tell ["Ball is at " ++ (show n)]
pure rp
我正在尝试按照 this paper 进行函数式响应式编程,但我仍然停留在第 4.2 节中的第二个示例上。
我得到了第一个例子 reader 变压器和 运行:
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
一些措辞
当你有一个转换器堆栈时,你必须 "lift" 你的操作到 运行 内部 monad 函数。例如:
type MyMonad a = Transformer1 (Transformer2 IO) a
这里的堆栈是IO的Transformer2的Transformer1。 "outer" monad 是 Transformer1,它用 IO 的最内层(或基础,底部)monad 包装 Transformer2。在您的情况下,堆栈实际上是某个未知 monad m
的 Reader 的 Writer,一切都很好。
现在,如果我们想从函数 g :: MyMonad
中 运行 f :: Transformer2 IO a
,我们必须 lift f
。同样,如果我们有 getLine :: IO String
并且我们希望 运行 从 g :: Transformer1 (Transformer2 IO) a
中得到它,那么我们可以 lift (lift getLine)
.
提升
如果导入 Control.Monad.Trans.Class
,则可以提升 ReaderT 操作。例如 lift (asks ...)
而不是 asks ...
.
这确实很有帮助。您评论的错误可能是由于在 checkHitR
.
asks
还有一个类型错误
完成提升后出现错误:
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
没有 return 值 rp
(我认为它应该)。解决这个问题给了我们最终的代码:
module Main where
import FRP.BearRiver
import Control.Monad.Trans.Class
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 +) <$> lift (asks leftPlayerPos))
checkHitR n = do
rp <- lift (asks rightPlayerPos)
when (rp > n) $ tell ["Ball is at " ++ (show n)]
pure rp