2017-10-21 59 views
0

我很新的Haskell,我正在写一个程序,我想创建一个日志消息的时间,并有可能appand文本到当前味精,这样只有信息会改变,但时间会保持创作的时间。 我试图执行以下操作:写我自己的日志数据类型haskell

data Msg = MNothing | MJust UTCTime String 

M是Message,并为MNothing的原因是为了将有一个空消息的可能性。

我还写道:

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

这样我可以使用mappend了两条消息,这将需要时间最早从消息。

我的问题是:

  1. 随着消息类型,我无法创建一个MJust变量,原因是调用getCurrentTime回报IO UTCTime,我想有UTCTime。我该如何解决这个问题?

  2. 我只能concat 2短信息,但它是一种毫无意义的话,是有可能能够Concat的Msg正常String(或[Char])?

我是新来的Haskell所以也许我失去了一些东西?谢谢。

+0

看来你尚未涵盖Haskell中的一些基本主题,特别是单子。我建议避免使用'IO',直到你至少读过[学习你的Haskell章节](http://learnyouahaskell.com/input-and-output),或者甚至是[关于monads的章节]( http://learnyouahaskell.com/a-fistful-of-monads)。 – AJFarmar

回答

4

随着消息类型,我有truble创建MJust变量,则 原因是调用getCurrentTime返回IO UTCTime,我想 有UTCTime。我该如何解决这个问题?

存在用于IO多项功能,可帮助解决这些“不匹配” (他们是更普遍的工作对于其他类型的为好,但现在不引起我们的关注。)

的重要的想法是,你不提取出IO的值。取而代之的是,您可以在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 

在你的情况,你可以这样

liftA2 MJust getCurrentTime (pure "somestring") 
创建 IO Msg类型的值

请记住,你没有得到UTCTime满分IO。相反,你需要在IO之内提供你需要的一切。

还存在着更为灵活的功能/操作(>>=)(称为“绑定”),让你构建复合IO操作,其中第二操作依赖于由第一个返回值:

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

请注意,我们可以根据IO a的结果决定执行什么IO b

一个简单的例子:

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

又一次的IO Msg

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

使用(>>=)我们可以构造非常相似的语句块命令式语言中的操作序列。但是编写所有那些(>>=)可能会不稳定,所以有一点名为do-notation的语法糖让事情变得更简单。

在DO-符号的IO Msg

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

这里<-并不像(>>=)但语法糖的一部分的实际操作。

+0

至于b)你可以简单地在'Monoid''接口“之外编写一个类型为'String - > Msg - > Msg'的函数。 – danidiaz

+0

谢谢。你的通讯真的有帮助! 我只有一个问题:你说我可以写:'getCurrentTime >> = \ theTime - > pure(MJust theTime“foo”)'我想创建我自己的monad,所以我可以使用>> =以便我认为它会比使用monoid和mappend更好。 你认为我能做到吗?如果可以,我需要成功吗? –

+0

@DvirItzko你的'Msg'类型doesn'因为时间很难“粉碎”,也许你可以使用列表'[Msg]'?列表自动是monoids。 已经有一个叫'Writer'的类型让你累积monoidal “记录”作为做其他事情的副作用http://hackage.haskell.org/package/transformers-0.5.5.0/docs/Control-Monad-Trans-Writer-Strict.html#t:Writer如果你想执行IO的东西,你会需要“变压器”变体:http://hackage.haskell .org/package/transformers-0.5.5.0/docs/Control-Monad-Trans-Writer-Strict.html#t:WriterT – danidiaz

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) 

然后用字符串Concat的,你可以使用fmap

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

我有一个问题。现在我无法使用Show查看消息。 之前,我有 '实例展(味精),其中 秀(MNothing)= “” 秀(MJust TS)=示出了T + s' 但现在不工作,我得到: 'Couldn” t与实际类型'a'匹配的预期类型'[Char]' 'a'是一个刚性类型变量,由 实例声明在Server.hs中绑定:41:10 相关绑定包括 s :: a Server.hs:43:19) show :: Msg a - > String(绑定在Server.hs:42:5) 在'(++)'的第二个参数中,即's' 在表达式中: show t ++ s' –

+0

我不会为此使用'show',它通常输出有效的Has凯尔代码 - 只需在数据decl上使用'deriving(Show)'。然后为你的自定义渲染定义'renderMsg :: Msg String - > String'。 – luqui