我从Haskell开始,我需要使用ReaderT
和StateT
Monads帮助拼接功能。
理想情况下,如果可能的话,所有函数都将具有相同的签名(我理解Monads应该帮助的那些),并且能够读取环境并改变状态。
下面的代码应该只使用初始环境openClientSocket
在initialNetwork
中打开一个套接字,在链中注入socket
和address
,然后调用作为参数传递的“next”函数func
(在本例中为函数sendMsg
)。
但是我面临着多个问题:
a)如何调用func
中传递的openClientConnection
?
b)HNT
Monad与其他Monad组成(?)。我如何阅读和操纵内蒙纳德?
有人可以请帮我修复此代码,如果可能的话,导出/解释“理想”模式以实现主题中描述的目标。
非常感谢
湾
import Control.Monad.Reader
import Control.Monad.State
import Network.Socket
import Network.Multicast
_MULTICAST_IP_ADDR_ :: HostName
_MULTICAST_IP_ADDR_ = "224.0.0.99"
_MULTICAST_PORT_ :: PortNumber
_MULTICAST_PORT_ = 9999
data NetworkEnv = NetworkEnv {
getMulticastIP :: HostName,
getMulticastPort :: PortNumber
} deriving (Show)
type NetworkEnvT = ReaderT NetworkEnv
data ClientSocket = ClientSocket {
getClientSocket :: Socket,
getAddress:: SockAddr
} deriving (Show)
type ClientSocketT = StateT ClientSocket
type HNT m = ClientSocketT (NetworkEnvT m)
initialNetwork :: NetworkEnv
initialNetwork = NetworkEnv { getMulticastIP = _MULTICAST_IP_ADDR_, getMulticastPort = _MULTICAST_PORT_ }
openClientConnection :: HNT m a -> m a
openClientConnection func = do
env <- ask
(sock, addr) <- liftIO $ multicastSender (getMulticastIP env) (getMulticastPort env)
put $ ClientSocket sock addr
func -- <== How do I call func (sendMsg) here ??
sendMsg :: String -> HNT IO ()
sendMsg msg = do
NetworkEnv ip port <- ask
ClientSocket sock addr <- get
_ <- liftIO $ sendTo sock msg addr
liftIO $ print "done"
doRun = runReaderT ( openClientConnection . (sendMsg "Hello") ) initialNetwork
答案 0 :(得分:0)
我管理下面的解决方案;我确信它可以改进,错误处理不完全到位,但它确实遵守合同。
从我的所有阅读材料中,真正,真正地帮助我的是来自MartinGrabmüller的this paper并意识到该程序在Monad中运行 :它不是函数调用的参数(多年的OO编程和注入调用)
import Control.Monad.Reader
import Control.Monad.State
import Control.Monad.Writer
import Control.Monad.Error
import Network.Socket
import Network.Multicast
_MULTICAST_IP_ADDR_ :: HostName
_MULTICAST_IP_ADDR_ = "224.0.0.99"
_MULTICAST_PORT_ :: PortNumber
_MULTICAST_PORT_ = 9999
data NetworkEnv = NetworkEnv {
getMulticastIP :: HostName,
getMulticastPort :: PortNumber
} deriving (Show)
data ClientSocket = ClientSocket {
getClientSocket :: Socket,
getAddress:: SockAddr
} deriving (Show)
type HNError = String
type LogMessages = [String]
type HNT a = ReaderT NetworkEnv (ErrorT HNError (WriterT LogMessages (StateT ClientSocket IO))) a
runHNT :: ClientSocket -> NetworkEnv -> HNT a -> IO( (Either HNError a, LogMessages), ClientSocket)
runHNT st env app = runStateT (runWriterT ( runErrorT (runReaderT app env) )) st
initialNetwork :: NetworkEnv
initialNetwork = NetworkEnv { getMulticastIP = _MULTICAST_IP_ADDR_, getMulticastPort = _MULTICAST_PORT_ }
initialState :: ClientSocket
initialState = ClientSocket undefined undefined
openClientConnection :: HNT ()
openClientConnection = do
env <- ask
(sock, addr) <- liftIO $ multicastSender (getMulticastIP env) (getMulticastPort env)
put $ ClientSocket sock addr
sendMsg :: String -> HNT ()
sendMsg msg = do
ClientSocket sock addr <- get
_ <- liftIO $ sendTo sock msg addr
tell ["Sent " ++ msg ++ " to socket" ]
myApp :: HNT ()
myApp = do
env <- ask
liftIO $ print (show env)
doRun :: IO ((Either HNError (), LogMessages), ClientSocket)
doRun = runHNT initialState initialNetwork ( openClientConnection >> sendMsg "Hello" >> myApp )