2012-02-24 9 views
9

Một kích thích với lười biếng IO bắt đến sự chú ý của tôi thời gian gần đâyStrict fmap chỉ sử dụng functor, không Monad

import System.IO 
import Control.Applicative 

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

Do lười biếng IO, các bản in chương trình trên không có gì. Vì vậy, tôi tưởng tượng điều này có thể được giải quyết với một phiên bản nghiêm ngặt của fmap. Và quả thực, tôi đã đưa ra chỉ là một combinator ví dụ:

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) 

Thay <$> với <$!> không thực sự làm giảm bớt các vấn đề. Tuy nhiên, tôi không hài lòng. <$!> có giới hạn Monad, cảm giác quá chặt; nó đồng hành <$> chỉ yêu cầu Functor.

Có cách nào để viết <$!> không có ràng buộc Monad không? Nếu có, làm thế nào? Nếu không, tai sao không? Tôi đã cố gắng ném nghiêm khắp nơi, không có kết quả (mã sau không công việc như mong muốn):

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)" là chính xác 'id', do đó không có tác dụng. –

+0

Điều này có vẻ là một định nghĩa rất lạ của <$!> đối với tôi. Thay vào đó, tôi sẽ sử dụng "f <$!> m = forceM (liftM f m)". Điều này cũng giải quyết vấn đề của bạn và có vẻ hợp lý hơn trong các ngữ cảnh khác. Tôi nghi ngờ bạn không thể xác định điều này cho các functors, mặc dù. – lpsmith

Trả lời

8

Tôi không nghĩ rằng nó có thể, và cũng là monadic forceM không hoạt động cho tất cả monads:

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 

Và việc đánh giá:

Prelude Force> test 
1 

forceM cần một nghiêm ngặt đủ (>>=) để thực sự buộc kết quả của đối số của nó. Functor thậm chí không có (>>=). Tôi không thấy làm thế nào người ta có thể viết một hiệu quả forceF. (Điều đó không chứng minh điều đó là không thể, tất nhiên.)