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