作者:胖儿的小金子 | 来源:互联网 | 2022-12-09 15:43
在Haskell中是否存在表达以下代码的惯用方法?
main :: IO ()
main = loop initState1 initState2 initState3
loop :: State1 -> State2 -> State3 -> IO ()
loop s1 s2 s3 = do
s1' <- runService1 s1
s2' <- runService2 s2
s3' <- runService3 s3
loop s1' s2' s3'
这段代码非常冗长,所以我可能会做一些奇怪的事情.
1> Gurkenglas..:
main = fix (zipWithM ($) >=>)
[runService1, runService2, runService3]
[initState1 , initState2 , initState3 ]
比较fix . (>>=) :: IO a -> IO b
,这是forever
.
编辑:这仅在State1
= State2
=时有效State3
.如果没有,data-fix
允许:
main = fix (traverse unFix >=>)
[ana runService1 initState1, ana runService2 initState2, ana runService3 initState3]
2> leftaroundab..:
我的做法是,您可能希望以适当的状态monad来推动该状态。该lens
库使访问它变得容易:
{-# LANGUAGE TemplateHaskell #-}
import Control.Lens.TH
import Control.Monad.Trans.State
data AllState = AllState { _s? :: State0, _s? :: State1, _s? :: State2 }
makeLenses ''AllState
loop :: StateT AllState IO ()
loop = do
s? <~ runService0 <$> use s?
s? <~ runService1 <$> use s?
s? <~ runService2 <$> use s?
loop
main = evalStateT loop $ AllState initState0 initState1 initState2
这样一来,您不会在原始代码上花太多钱,但是如果您还为runService
动作指定合适的state-monad类型,它将变得更加方便:
runService0 :: StateT State0 IO ()
runService1 :: StateT State1 IO ()
runService2 :: StateT State2 IO ()
...然后您可以简单地使用以下zoom
机制:
loop :: StateT AllState IO ()
loop = do
zoom s? runService0
zoom s? runService1
zoom s? runService2
loop
或古尔肯拉斯(Gurkenglas)建议
loop = forever $ do
zoom s? runService0
zoom s? runService1
zoom s? runService2