2013-04-25 2 views
2

У меня есть список [(String, [String], IO Int)], который я бы хотел сортировать. sortBy (\x -> ...) list требует от IO использовать внутреннее значение IO Int, что означает, что я не могу вернуть Ordering, но только IO Ordering в функцию sortBy. Есть ли способ отсортировать список?Как отсортировать список на основе значения IO Int

+0

Если ваша функция сравнения находится в 'IO', это означает, что сравнение может меняться каждый раз, когда вы это делаете. Как вы можете отсортировать список, если не можете воспроизводить два элемента? –

+0

Я думаю, что мы говорим здесь абстрактно. Как вы будете делать то, что хотите делать на обычном языке, таком как Python или Java или Javascript? – ErikR

+1

Почему вы не можете запустить действие «IO», получить «Int», а затем отсортировать список? Вы действительно хотите получить потенциально различный 'Int' каждый раз, когда вы сравниваете элемент списка? –

ответ

7

Третий элемент каждого кортежа - IO Int, поэтому его значение зависит от внешнего мира. Так что заказать отсортированного списка зависит от внешнего мира. Нет, нет способа сделать [(String, [String], IO Int)], который сортируется по значению IO Int.

Что вы можете сделать, это значение IO [(String, [String], Int)], а затем поднимите sortBy функцию вIO монады, чтобы дать вам еще IO [(String, [String], Int)], что позволит получить список отсортированных по Int. Это не чистый список, но вы можете ввести любую другую чистую функцию в монаду IO, чтобы делать на ней произвольные чистые вычисления.

Что-то, как это будет делать:

import Control.Applicative 
import Data.List 

l :: [(String, [String], IO Int)] 
l = [("Foo", [], return 2), ("Bar", [], return 1)] 

f :: Monad m => (a, b, m c) -> m (a, b, c) 
f (x, y, ioz) = ioz >>= \z -> return (x, y, z) 

sl = sortBy (\(x, y, z) (x', y', z') -> compare z z') <$> mapM f l 

Я должен упомянуть, так как это может быть не очевидно, что это будет запускать IO Int действия в том порядке, в котором они появились в списке изначально. Но чтобы отсортировать их, вы должны запустить их, чтобы получить значения Int, и их нужно запустить в примерно.

+0

Этот подъем монады был именно тем, что мне нужно, спасибо. – Witiko

+0

@Witiko Как правило, я стараюсь программировать в Haskell. Напишите все вычисления как чистые функции. В какой-то момент ваши вычисления зависят от значений «IO», но вы пытаетесь поднять чистые функции в монаду «IO», чтобы выполнить всю реальную работу как можно скорее. Это означает, что вы делаете большую часть своей работы, как будто 'IO' не существует, и даже когда вы пишете код« IO », вы, надеюсь, просто снимаете чистые функции и проводя результаты, а не повторно реализуете 'IO' версии вещей. – Ben

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