2012-02-24 10 views
9

一つの刺激が原因怠惰なIOに最近厳密FMAPは、怠惰なIOでないモナド

import System.IO 
import Control.Applicative 

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

私の注意をキャッチし、上記のプログラムは、何も出力しません。だから私はこれがfmapの厳密なバージョンで解決できると思いました。そして実際、私はちょうどそのようなコンビネータを思い付くんでした:

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) 

が実際に問題を軽減ん<$!><$>を交換します。しかし、私は満足していません。 <$!>にはMonadという制約があります。同義語<$>Functorのみ必要です。

<$!>には、Monadの制約がありません。そうなら、どうですか?そうでない場合は、どうしてですか?私は無駄(は、必要に応じていない仕事がない、次のコード)に、あらゆる場所に厳しさを投げて試してみた:

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)"は正確には "id"です。 –

+0

これは私にとって<$!>の非常に奇妙な定義のようです。代わりに "f <$!> m = forceM(liftM f m)"としてください。これはまたあなたの問題を解決し、他の文脈ではもっと賢明なようです。私はあなたがファンクタのためにこれを定義することはできないと思う。 – lpsmith

答えて

8

私はそれが可能だとは思わない、ともモナドforceMは動作しません。

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 

と評価:

Prelude Force> test 
1 

十分に厳格な01を必要とするforceMすべてのモナドのためのは実際にその引数の結果を強制します。 Functorには(>>=)もありません。私はどのように効果的に書くことができないのか分かりません。forceF。 (それはもちろん不可能であることを証明するものではありません)

関連する問題