Haskell - 可能/只是递归

use*_*652 2 monads haskell maybe

我读了一些关于monad的帖子和博客,也许,只是,没什么..但是没有真正得到它:/在给定的代码中,我必须实现"latestActivity"函数.在我看来它应该工作,但我不知道如何正确使用"只是".也许有人能够帮助我.

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
Run Code Online (Sandbox Code Playgroud)

lef*_*out 5

@rightfold提供了一个可能的解决方案,但请注意您的方法不是非常惯用的Haskell."否则删除最后一个侦听器"是程序性思考,而不是你想要推理Haskell函数的方式.这不是真正在代码中发生的事情,无论如何,你不能删除的东西在Haskell,但需要建立一个新的列表中的每个迭代:作为一个结果,这是非常低效的,因为两者lastinit需要遍历整个列表别的可以做之前.

基本上,你正在做的是从列表中搜索,从前到后.因此,显而易见的首要任务是反转列表,以便您可以像以前一样进行前后搜索(并且列表已经过优化).

latestActivity user = earliestAct . reverse
 where earliestAct = ...
Run Code Online (Sandbox Code Playgroud)

现在,这也可以实现

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

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

       earliestAct = fmap _messageContent . find ((==user) . _userName)
    
    Run Code Online (Sandbox Code Playgroud)

    在这里,我已经使用了从找到的消息中提取内容的Functor实例Maybe,如果有的话.