2

我读了一些关于 monad 的帖子和博客,也许,只是,什么都没有……但并没有真正明白:/ 在给定的代码中,我必须实现“latestActivity”-function。在我看来,它应该可以工作,但我不知道如何正确使用“Just”。也许有人能够帮助我。

module LatestActivity where
{-
Write a function 'latestActivity' that finds that last time a specific user
has sent a message. It is given a user name and a list of messages. A message
consists of the time it was sent, the user name of the user who sent it and
the message content. If there is no message from the given user in the list
the function yields 'Nothing'. Otherwise it yields 'Just' the latest time stamp
of the messages of that user in the list.
-}

import Data.List (sort)

-- | A time stamp represented as an 'Integer'
type AbsoluteTime = Integer
-- | A user name represented as a 'String'
type UserName = String

-- | A message consists of the time it was sent, the user who sent it
--   and the actual message content.
data Message = Message {
    _timeStamp :: AbsoluteTime,
    _userName :: UserName,
    _messageContent :: String}

-- | Given a user name and a list of sent messages finds 'Just' the last time
--   a user has sent a message or 'Nothing' if the user has not sent anything.
--   The messages are not assumed to be ordered in any way.
latestActivity :: UserName -> [Message] -> Maybe AbsoluteTime
latestActivity _ [] = Nothing 
latestActivity x y = 
    if (x == (_userName (last y)))      -- x equals username in last list element?
        then (_timeStamp (last y))      -- print it
        else (latestActivity x init y)  -- otherwise delete last listelement, recursion till list is empty
4

2 回答 2

5

@rightfold 提供了一个可能的解决方案,但请注意,您的方法不是非常惯用的 Haskell。“否则删除最后一个列表元素”是程序性思维,而不是您想要推理 Haskell 函数的方式。无论如何,这在您的代码中并没有真正发生,您不能在 Haskell 中删除内容,但需要在每次迭代时构建一个新列表:因此,它的效率极低,因为两者都last需要init遍历整个列表才能完成其他任何操作.

基本上,您所做的是从后到前搜索列表。因此,显而易见的第一件事是,反转列表,以便您可以按照习惯从前到后搜索(并且优化了列表)。

latestActivity user = earliestAct . reverse
 where earliestAct = ...

现在,这可以实现

  • 通过简单的模式匹配递归列表:

       earliestAct [] = Nothing
       earliestAct (Message t user' txt : msgs)
             | user' == user  = Just txt
             | otherwise      = earliestAct msgs
    
  • 或者:正如我所说,这只是一个标准搜索。那么为什么不使用标准find功能呢!

       earliestAct = fmap _messageContent . find ((==user) . _userName)
    

    在这里,我使用 的Functor实例Maybe从找到的消息中提取内容(如果有的话)。

于 2014-05-29T14:03:03.950 回答
2

只需添加... Just:v

latestActivity :: UserName -> [Message] -> Maybe AbsoluteTime
latestActivity _ [] = Nothing 
latestActivity x y = 
    if x == _userName (last y)
        then Just (_timeStamp (last y))
        else latestActivity x (init y)
于 2014-05-29T13:51:25.067 回答