2017-02-19 12 views
0

У меня есть следующий код, который берет список, проверяет, превышает ли значение каждого элемента значение avg, и это так, печатает val - avg. Я уже реализовал его с рекурсией, я хотел бы преобразовать его, чтобы использовать функцию map.Использовать карту вместо рекурсии

loop [] = return() 
loop (x:xs) 
     | x > average = print (x - average) >> loop xs 
     | otherwise = loop xs 

Любое предложение?

+0

Хорошим правилом, чтобы жить, является, как можно больший, из вашего чистого кода. В этом духе я бы написал «mapM_ print». foo где foo = map (вычесть среднее значение). фильтр (> средний) '. Это действительно помогает писать типы вещей, которые вы уже написали, а также типы вещей, которые вы хотите написать: поэтому вы говорите, что хотите использовать «карту», ​​то какой тип функции вы намереваетесь перейти на 'map'? Не похоже, что вы думали, что далеко впереди – jberryman

ответ

7

Обратите внимание, что каждый шаг loop выполняет две вещи одновременно: они (возможно) генерируют действие печати из каждого элемента списка, а затем объединяют это действие с оставшимися (используя (>>)). Если вы хотите написать loop в терминах map, вам необходимо отключить эти два подэтапа. Например, вы можете определить функцию ...

printDiffIfAboveAvg :: Double -> IO() 

..., а затем применить его ко всем элементам списка с map printDiffIfAboveAvg. Это даст вам список действий, типа [IO()], что вам нужно будет объединить в одно общее действие:

runAllActions :: [IO()] -> IO() 

runAllActions уже существует в базовой библиотеке, в более общей версии под названием sequence_:

sequence_ :: (Foldable t, Monad m) => t (m a) -> m() 

Итак, у вас было бы loop = sequence_ . map printDiffIfAboveAvg. На самом деле, есть и другая функция в базовой библиотеке ...

mapM_ :: (Foldable t, Monad m) => (a -> m b) -> t a -> m() 

... который выполняет именно эту комбинацию sequence_ и map.