Какова цель трансформатора IdentityT?

Просматривая пакет трансформаторов, я нашел этот монадный трансформатор под названием IdentityT.

Хотя я понимаю, как используется монада Identity (например, State является просто псевдонимом для StateT Identity) и как работают монадные трансформаторы вообще, я не знаю, как это относится к IdentityT.

Поскольку это не в MTL, я предполагаю, что он был добавлен там только для полноты и не имеет практического применения. Это правильно?

Ответ 1

Хорошо связанная документация говорит

Это полезно для функций, параметризованных монадным трансформатором.

Хотя я не знаю ни о каких ситуациях, где это на самом деле. Теоретически, если у вас есть такая функция, как foo :: (MonadTrans t, Monad m) => t m a -> b для некоторого полезного b, то вы можете захотеть "опустить ее вниз" по существу m a -> b с помощью t = IdentityT.

Но IdentityT соответствует MonadTrans, что Identity соответствует Monad. Это "проходной" трансформатор, поскольку Identity является "проходной" монадой. Просто проверьте источник; это довольно просто. IdentityT SomeMonad a должен вести себя одинаково с SomeMonad a, с той лишь разницей, что существует дополнительный тип newtype (который, конечно же, удаляется во время компиляции)

Ответ 2

Здесь предлагается использовать (предположительно, источник IdentityT: http://www.haskell.org/pipermail/libraries/2007-June/007563.html

Основное использование, по-видимому, заключается в обеспечении гибкости на уровне исходного кода, например. кто-то может отредактировать источник на xmonad и заменить свой собственный UserT без редактирования слишком большого кода.

Я попытался понять, как это может работать для библиотеки - вы можете использовать его, чтобы предоставить местозаполнитель для вставки монады в середине стека, но я не уверен в этом. Вот мой надуманный пример:

{-# LANGUAGE GeneralizedNewtypeDeriving #-}

module Main where

import Control.Monad.State
import Control.Monad.List
import Control.Monad.Reader

type X m a = StateT Int (m IO) a

something :: (Monad (m IO), MonadIO (m IO)) => (m IO) Int -> X m Int 
something a = do
        x <- lift a
        put (x + 1)

        liftIO $ print x
        return x



listSomething = something $ ListT (mapM return [1,2,3,4])
plainSomething = return 5 :: IdentityT IO Int

main = do 
    x <- runListT (execStateT listSomething 3)
    print x 

    y <- runIdentityT (execStateT plainSomething 3)
    print y

runIdentity $ mapM (return . (+1)) [1..100]