2010-07-01 2 views
7

Существует ли традиционный способ сопоставления функции, использующей IO? В частности, я хотел бы сопоставить функцию, возвращающую случайное значение. Использование обычной карты приведет к выводу типа ([IO b]), но для распаковки значений в списке из IO мне нужно что-то типа (IO [b]). Поэтому я написал ...Отображение IO в Haskell

mapIO :: (a -> IO b) -> [a] -> [b] -> IO [b] 
mapIO f [] acc = do return acc 
mapIO f (x:xs) acc = do 
    new <- f x 
    mapIO f xs (new:acc) 

... который отлично работает. Но, похоже, должно быть решение для этого встроенного в Haskell. Например, пример использования:

getPercent :: Int -> IO Bool 
getPercent x = do 
    y <- getStdRandom (randomR (1,100)) 
    return $ y < x 

mapIO (\f -> getPercent 50) [0..10] [] 
+9

В будущем попробуйте [Hoogle] (http://haskell.org/hoogle/?hoogle= (a + -% 3E + IO + b \) + -% 3E + \ [a \] + -% 3E + IO + \ [b \]), чтобы выяснить, существует ли какая-то кажущаяся очевидная функция (потому что они обычно делают). Это потрясающе полезно! –

+0

Спасибо, это выглядит как отличный ресурс! – unignorant

+1

Кроме того, зайдите в Hayoo - это похоже на Hoogle, но проверяет вещи по-разному. – BMeph

ответ

21

Стандартный путь через:

Control.Monad.mapM :: (Monad m) => (a -> m b) -> [a] -> m [b] 

который реализуется в терминах последовательности:

sequence :: (Monad m) => [m a] -> m [a] 
+0

Спасибо! Именно то, что я искал. – unignorant

+1

, кстати, 'mapM' уже находится в Prelude – newacct

9

Просто, чтобы добавить к ответу Дона, hake посмотрите на функцию mapM_, которая делает именно то, что делает mapM, но отбрасывает все результаты, поэтому вы получаете только побочные эффекты.

Это полезно, если вы хотите, чтобы выполнялись вычисления (например, вычисления IO), но не заинтересованы в результате (например, открепляющие файлы).

А также см. forM и forM_.

+7

, а mapM_ работает в пространстве с постоянным стеком, тогда как mapM нуждается в линейном стеке, аналогично для sequence_ vs. sequence. –

+0

@Simon, спасибо, что упомянули об этом. Я всегда очень внимательно смотрю на свой mapM, чтобы убедиться, что список невелик или попытаться использовать рефакторинг для использования mapM_. –