10

最近私の注意を引いた怠惰なIOの1つの苛立ち

import System.IO
import Control.Applicative

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

遅延 IO のため、上記のプログラムは何も出力しません。したがって、これは の厳密なバージョンで解決できると想像しました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)
4

1 に答える 1

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

forceM(>>=)引数の結果を実際に強制するのに十分な厳密さが必要です。Functorもありません(>>=)。効果的なものをどのように書くことができるかわかりませんforceF。(もちろん、それが不可能であることを証明するものではありません。)

于 2012-02-24T01:01:55.913 に答える