2012-02-24 18 views
9

Una irritación con IO perezoso cogió a mi atención recientementefmap estricto utilizando sólo Functor, no Mónada

import System.IO 
import Control.Applicative 

main = withFile "test.txt" ReadMode getLines >>= mapM_ putStrLn 
    where getLines h = lines <$> hGetContents h 

Debido a la pereza IO, el programa imprime por encima de nada. Así que imaginé que esto podría resolverse con una versión estricta de fmap. Y, de hecho, yo he venido para arriba con apenas un combinador tales:

forceM :: Monad m => m a -> m a 
forceM m = do v <- m; return $! v 

(<$!>) :: Monad m => (a -> b) -> m a -> m b 
f <$!> m = liftM f (forceM m) 

Sustitución <$> con <$!> en efecto aliviar el problema. Sin embargo, no estoy satisfecho. <$!> tiene una restricción Monad, que se siente demasiado apretada; es compañero <$> requiere solo Functor.

¿Hay una manera de escribir <$!> sin la limitación Monad? Si es así, ¿cómo? ¿Si no, porque no? He intentado tirar rigor por todo el lugar, sin ningún resultado (siguiente código no trabajo como se desee):

forceF :: Functor f => f a -> f a 
forceF m = fmap (\x -> seq x x) $! m 

(<$!>) :: Functor f => (a -> b) -> f a -> f b 
f <$!> m = fmap (f $!) $! (forceF $! m) 
+2

"(\ x -> seq x x)" es precisamente 'id', por lo que no ayuda. –

+0

Esto me parece una definición muy extraña de <$!>. Me gustaría ir con "f <$!> m = forceM (liftM f m)" en su lugar. Esto también resuelve tu problema y parece mucho más sensato en otros contextos. Sin embargo, sospecho que no puedes definir esto para los funtores. – lpsmith

Respuesta

8

no creo que es posible, y también el monádico forceM no funciona para todas las mónadas:

module Force where 

import Control.Monad.State.Lazy 

forceM :: Monad m => m a -> m a 
forceM m = do v <- m; return $! v 

(<$!>) :: Monad m => (a -> b) -> m a -> m b 
f <$!> m = liftM f (forceM m) 

test :: Int 
test = evalState (const 1 <$!> undefined) True 

Y la evaluación:

Prelude Force> test 
1 

forceM necesita suficiente una estricta (>>=) para forzar realmente el resultado de su argumento. Functor ni siquiera tiene un (>>=). No veo cómo se podría escribir un efectivo forceF. (Eso no prueba que sea imposible, por supuesto.)