编写我自己的日志数据类型haskell

时间:2017-10-21 13:08:55

标签: haskell

我对Haskell很陌生,而且我正在编写一个程序,我希望在其中创建一个具有创建时间的日志消息,并且可以将当前消息的应用和文本设置为只有消息会改变,但时间将保持创造的时间。 我试着做以下事情:

 data Msg = MNothing | MJust UTCTime String 

M用于消息,MNothing的原因是可能会出现空消息。

我还写道:

instance Monoid Msg where
    mempty = MNothing
    (MJust t s) `mappend` (MJust t' s') = MJust (minimum (t,t'))  (s++s')

通过这种方式,我可以将mappend用于两条消息,这将是消息中最早的时间。

我的问题是:

  1. 使用Msg类型,我在创建MJust变量时遇到问题,原因是调用getCurrentTime会返回IO UTCTime,我希望{ {1}}。我该如何解决这个问题?

  2. 我只能UTCTime两个Msgs,但这样做是没有意义的,是否可以将concat与正常Msg联系起来(或{ {1}})?

  3. 我是Haskell的新手,所以也许我错过了什么?感谢。

2 个答案:

答案 0 :(得分:4)

  

使用Msg类型,我正在创建一个MJust变量   原因是调用getCurrentTime返回IO UTCTime,我想要   有UTCTime。我该如何解决这个问题?

IO有许多功能可以帮助解决这些"不匹配问题"  (它们更为通用,也适用于其他类型,但现在我们并不关心。)

重要的一点是,您不能从IO中提取值。而不是那样,你提升"功能 in IO

例如,fmap函数(也称为liftA)转换函数,使其在IO内工作:

fmap :: (a -> b) -> IO a -> IO b

liftA2让你将两个参数函数应用于IO内的参数:

liftA2 :: (a -> b -> c) -> IO a -> IO b -> IO c

return(也称为pure)允许您在IO内添加任何值:

return :: a -> IO a

在您的情况下,您可以像这样创建IO Msg类型的值

liftA2 MJust getCurrentTime (pure "somestring")

请记住,您不会从UTCTime中获得IO。相反,您需要在IO内提供所需的一切。

还存在更灵活的函数/运算符(>>=)(称为" bind"),它允许您构建复合IO运算,其中第二个运算取决于返回的值第一个:

(>>=) :: IO a -> (a -> IO b) -> IO b

请注意,我们可以根据IO b的结果确定要执行的IO a

一个简单的例子:

getLine >>= \msg -> if msg == "foo" then putStr "yay" else putStr "nay"

再次IO Msg

getCurrentTime >>= \theTime -> pure (MJust theTime "foo")

使用(>>=),我们可以构造与命令式语言中的语句块非常相似的操作序列。但是编写所有(>>=)可以得到全面的,所以有一些叫做do-notation的语法糖会让事情变得更容易。

附加说明中的IO Msg

do theTime <- getCurrentTime 
   pure (MJust theTime "foo")

此处<-不是(>>=)之类的实际运算符,而是语法糖的一部分。

答案 1 :(得分:1)

至于(2),我解决这个问题的方法是让Msg成为Functor

data Msg a = MNothing | MJust UTCTime a

instance Functor Msg where
    fmap f MNothing = MNothing
    fmap f (MJust t x) = MJust t (f x)

然后使用字符串连接,您可以使用fmap

msg' = fmap (++ " in bed") msg