В качестве примера предположим, что я хочу написать монадическую и не монадическую карту по спискам. Я начну с монадического:
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?