Haskell - Может быть / Просто Рекурсия

Я читал несколько сообщений и блогов о монадах, может быть, просто ничего .. но на самом деле не понял: / В данном коде я должен реализовать функцию "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

person user3684652    schedule 29.05.2014    source источник
comment
Вы должны предоставить более подробную информацию о том, какие проблемы у вас есть с вашим текущим решением, например о любых сообщениях об ошибках, которые вы получаете от компилятора, или о неправильном поведении во время выполнения. Без этой информации людям потребуется гораздо больше времени, чтобы увидеть, что вы делаете неправильно, и помочь вам.   -  person GS - Apologise to Monica    schedule 02.06.2014


Ответы (2)


@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 для извлечения содержимого из найденного сообщения, если оно вообще есть.

person leftaroundabout    schedule 29.05.2014
comment
TY за такой хороший ответ! Ты прав! Но я новичок, только что выполнил пару задач, и я счастлив, если это сработает - не важно, насколько это эффективно xD Мне действительно нужно избавиться от этого итеративного мышления .. THX - person user3684652; 29.05.2014

Просто добавьте… 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)
person rightfold    schedule 29.05.2014
comment
Разве это не должно быть else latestActivity x (init y)? - person bheklilr; 29.05.2014
comment
omg .. ty ^^ Я уже пробовал поставить Just в эту позицию, но это не сработало .. так что после исправления скобок, как вы это сделали, все работает нормально. Спасибо - person user3684652; 29.05.2014