В качестве примера предположим, что я хочу написать монадическую и не монадическую карту по спискам. Я начну с монадического:
import Control.Monad
import Control.Monad.Identity
mapM' :: (Monad m) => (a -> m b) -> ([a] -> m [b])
mapM' _ [] = return []
mapM' f (x:xs) = liftM2 (:) (f x) (mapM f xs)
Теперь я хочу повторно использовать код для записи чистого map
(вместо повторения кода):
map' :: (a -> b) -> ([a] -> [b])
map' f = runIdentity . mapM' (Identity . f)
Что необходимо сделать, чтобы map'
был оптимизирован так, как если бы он был написанный явно как map
? В частности:
-
Нужно ли писать
{-# SPECIALIZE mapM' :: (a -> Identity b) -> ([a] -> Identity [b]) #-}
или GHC оптимизирует сам
map'
(полностью исключаяIdentity
)? -
Необходимо добавить что-нибудь еще (более прагмы)?
- Как я могу проверить, насколько хорошо скомпилированный
map'
оптимизирован по явно написанному коду дляmap
?