import Control.Monad
data Logger l a = Logger {runLogger :: (IO (),a,l)}
iologger :: (Show l)=> l->a->(a->b)->Logger l b
iologger l a f = Logger (print l,f a,l)
instance (Show l)=>Monad (Logger l) where
return a = iologger (show "") a id
logger>>=f = let (_,va,vl) = runLogger logger
in iologger vl va f上面的代码不能编译。我想做的东西是这样的(下面的代码是F#计算表达式)
let loggedWorkflow =
logger
{
let! x = 42
let! y = 43
let! z = x + y
return z
}因此,上面的代码记录了结果
type LoggingBuilder() =
let log p = printfn "expression is %A" p
member this.Bind(x, f) =
log x
f x
member this.Return(x) =
x但这在Haskell中不起作用,因为print需要Show限制。Writer monad也无法做到这一点,因为它是显式的。在您编写的每个代码中,您必须将tell。有什么想法吗?
发布于 2018-01-21 00:48:08
您可以使用RebindableSyntax以任何您想要的方式重新定义(>>=)。
请注意,这并不满足单数定律,除非您考虑在程序上忽略日志记录中的差异的等价关系。
这些return也有一些更多的噪音,因为没有去糖化成(>>=)的let!语法。
另外,为什么不在必要的地方调用log呢?
{-# LANGUAGE RebindableSyntax #-}
import qualified Control.Monad as Monad
import Prelude (IO, Show(show), (++), putStrLn, ($), fromInteger, Int, (+))
class CMonad m where
return :: a -> m a
(>>=) :: Show a => m a -> (a -> m b) -> m b
log :: Show a => a -> IO ()
log x = putStrLn $ "Expression is: " ++ show x
instance CMonad IO where
return = Monad.return
m >>= k = m Monad.>>= \a -> log a Monad.>> k a
main :: IO Int
main = do
x <- return (42 :: Int)
y <- return (43 :: Int)
z <- return (x + y)
return zhttps://stackoverflow.com/questions/48358101
复制相似问题