【问题标题】:Haskell - Maybe/Just RecursionHaskell - 也许/只是递归
【发布时间】:2014-05-29 13:42:05
【问题描述】:

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

【问题讨论】:

  • 您应该提供有关当前解决方案存在哪些问题的更多详细信息,例如从编译器获得的任何错误消息或运行时的错误行为。如果没有这些信息,人们就会花费更多时间来查看您做错了什么并为您提供帮助。

标签: haskell monads maybe


【解决方案1】:

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

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

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)
    

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

【讨论】:

  • TY 的好答案!你说的对!但我是初学者,刚刚完成了几项任务,如果它有效,我很高兴 - 不管它有多有效 xD 我真的需要摆脱那种迭代的思维方式.. THX
【解决方案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)

【讨论】:

  • 不应该是else latestActivity x (init y)吗?
  • omg.. ty ^^ 我已经尝试将“Just”放在那个位置,但它没有工作..所以在纠正括号后你的工作方式很好。 THX
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-04-18
  • 1970-01-01
  • 1970-01-01
  • 2021-02-18
  • 2011-07-12
  • 1970-01-01
相关资源
最近更新 更多