2016-11-09 2 views
0

Итак, я пытаюсь напечатать два значения, прежде чем использовать их. Вот два способа, которые работают отлично, но я чувствую, что есть другие способы, которыми я мог бы это сделать. Я знаю, что предлагаемый способ сделать это, скорее всего, делает блок с момента его изложения и является наименее сложным, но почему бы не увидеть, как еще?Haskell печатает и использует значение из монады

-- 1 
main = do 
    a <- m1 
    b <- m2 
    print a 
    print b 
    print $ f a b 

-- 2 
p x = print x >> return x 

main = print =<< liftM2 f (p =<< m1) (p =<< m2) 

Я также попытался это, но у них есть свои проблемы, я не совсем в состоянии понять, и там никогда не кажется, чтобы быть правильные вещи в цепи вместе.

main = print =<< foldl1 f . mapM p =<< sequence [m1, m2] 
main = print =<< on f p m1 m2 
main = print . curry (on f) =<< (uncurry (join (***)) p) m1 m2 

Я думаю, что on от Data.Function довольно близко к тому, что я хочу сделать, но я не знаю, как труба в двух монадических значений. Спасибо заранее за любые предложения.

Редактировать: Первый вопрос немного широк: как я могу переписать первый блок? Мой другой вопрос: как я могу извлечь два значения из монады в функцию, которая принимает два значения?
Если бы была функция, которая делала что-то вроде (m a, m a) -> m (a, a), то я думаю, что мог бы сделать curry (on f p) =<< thatfunction (m1, m2), но может быть и другой способ.

+0

Если это исключительно для целей отладки, то [ 'traceShowId'] (https://hackage.haskell.org/package/base/docs/Debug-Trace.html#v:traceShowId) из' отладки. Trace' может помочь. –

+0

@AlexisKing, если им нужен монадический контекст для чего-то другого, это кажется излишним, но относительным хорошим решением. – dfeuer

+4

В чем вопрос? –

ответ

0

Вы можете это:

main = (liftM2 f `on` (>>= p)) m1 m2 >>= print 
     where f = (++) 
      p x = print x >> return x 
      m1 = getLine 
      m2 = getLine 
  • liftM2 f создает версию f, чьи "аргументы" являются монадические значения.
  • on создает функцию, которая передает оба аргумента через (>>= p), прежде чем передавать их на liftM2 f.
  • Окончательный результат затем привязан к print.

В результате, в этом примере

  1. ждет линии, который необходимо ввести, а затем печатает, что линия
  2. Ожидает другой линии, который необходимо ввести, затем печатает , что линии
  3. Затем объединяет две строки, а затем выводит результат.
1

Вы можете создать несколько комбинаторы Аппликативный стиле, которые выполняют печать, если вы хотите, чтобы сделать вещи немного короче:

import Control.Monad.IO.Class (MonadIO(..)) 

(<*&>) :: (MonadIO m, Show a) => m (a -> b) -> m a -> m b 
mf <*&> mx = do 
    f <- mf 
    x <- mx 
    liftIO $ print x 
    return $ f x 

(<$&>) :: (MonadIO m, Show a) => (a -> b) -> m a -> m b 
f <$&> mx = pure f <*&> mx 

(имена, вероятно, оставляют желать лучшего, но я оставлю это . Вам)

с этими операторами, вы могли бы написать свой оригинальный пример, как это:

main = print $ f <$&> m1 <*&> m2 

ли не думаете, что вы это яснее (и, вероятно, до того, как часто вы используете этот шаблон).

Смежные вопросы