Constraints on <$> vs <$!>

Hello haskellers, I wonder why <$> and <$!> have different typeclass constraints? (<$>) :: Functor f => (a -> b) -> f a -> f b (<$!>) :: Monad m => (a -> b) -> m a -> m b

http://stackoverflow.com/questions/9423622/strict-fmap-using-only-functor-no...
seems to cover it.
On Mon, Aug 10, 2015 at 4:17 PM, Alexey Egorov
Hello haskellers,
I wonder why <$> and <$!> have different typeclass constraints?
(<$>) :: Functor f => (a -> b) -> f a -> f b (<$!>) :: Monad m => (a -> b) -> m a -> m b _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
-- Chris Allen Currently working on http://haskellbook.com

What about f <$!> x = (f $!) <$> x ? --Will
On Aug 10, 2015, at 14:20, Christopher Allen
wrote: http://stackoverflow.com/questions/9423622/strict-fmap-using-only-functor-no... seems to cover it.
On Mon, Aug 10, 2015 at 4:17 PM, Alexey Egorov
wrote: Hello haskellers, I wonder why <$> and <$!> have different typeclass constraints?
(<$>) :: Functor f => (a -> b) -> f a -> f b (<$!>) :: Monad m => (a -> b) -> m a -> m b _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
-- Chris Allen Currently working on http://haskellbook.com _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe

Prelude Control.Applicative> let f <$!> x = (f $!) <$> x Prelude Control.Applicative> :t (<$!>) (<$!>) :: Functor f => (a -> b) -> f a -> f b
On 10 Aug 2015, at 23:30, Will Yager
wrote: What about
f <$!> x = (f $!) <$> x
?
--Will
On Aug 10, 2015, at 14:20, Christopher Allen
wrote: http://stackoverflow.com/questions/9423622/strict-fmap-using-only-functor-no... seems to cover it.
On Mon, Aug 10, 2015 at 4:17 PM, Alexey Egorov
wrote: Hello haskellers, I wonder why <$> and <$!> have different typeclass constraints?
(<$>) :: Functor f => (a -> b) -> f a -> f b (<$!>) :: Monad m => (a -> b) -> m a -> m b _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
-- Chris Allen Currently working on http://haskellbook.com _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe

This doesn't buy you very much, unfortunately. (f $!) only forces its argument if the result is ever forced. So if the implementation of fmap doesn't force the function calls (and normally it won't, with no possible way to use the result for anything) then f x doesn't either; the arguments to those calls are not forced, and so the contents of the original structure remain unforced. For example: Prelude> let f x = (f $!) x() :: Functor f => (a -> b) -> f a -> f b Prelude> let z = const True [undefined]z :: [Bool] Prelude> case z of (_:_) -> "matched""matched"it :: String Prelude> z[*** Exception: Prelude.undefined The undefined bomb only goes off when I start to force the elements of z; prior to that no strictness has been gained, and the list contains a thunk as normal. In particular, this version of wouldn't help with the lazy IO problem described in that stackoverflow question Christopher linked earlier. -- Ben ----- Original Message ----- From: "Will Yager" To:"Christopher Allen" Cc:"haskell-cafe" Sent:Mon, 10 Aug 2015 14:30:49 -0700 Subject:Re: [Haskell-cafe] Constraints on vs What about f x = (f $!) x ? --Will On Aug 10, 2015, at 14:20, Christopher Allen wrote: http://stackoverflow.com/questions/9423622/strict-fmap-using-only-functor-no... [2] seems to cover it. On Mon, Aug 10, 2015 at 4:17 PM, Alexey Egorov wrote: Hello haskell ers, I wonder why and have different typeclass constraints? () :: Functor f => (a -> b) -> f a -> f b () :: Monad m => (a -> b) -> m a -> m b _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org [4] http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe [5] -- Chris Allen Currently working on http://haskellbook.com [6] _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org [7] http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe [8] Links: ------ [1] mailto:cma@bitemyapp.com [2] http://stackoverflow.com/questions/9423622/strict-fmap-using-only-functor-no... [3] mailto:electreg@list.ru [4] mailto:Haskell-Cafe@haskell.org [5] http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe [6] http://haskellbook.com [7] mailto:Haskell-Cafe@haskell.org [8] http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe

On Tue, Aug 11, 2015 at 5:32 AM, Ben
In particular, this version of <$!> wouldn't help with the lazy IO problem described in that stackoverflow question Christopher linked earlier.
We can say more. The version of <$!> that the SO question author himself gives as a solution to the lazy IO problem doesn't really work. I'm referring to: 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) and changing out <$> for <$!> in getLines h = lines <$> hGetContents h With the change, all of short files get read, thanks to file buffering. Like the first 4K or so. Bad surprise when you try it with longer files. There's a right path through lazy I/O and a wrong one. Rather than take the wrong one, better the following instead: main = mapM_ putStrLn =<< lines <$> readFile "test.txt" But if withFile is absolutely needed (experts only): main = withFile "test.txt" ReadMode getAndPutLines where getAndPutLines :: Handle -> IO () getAndPutLines h = mapM_ putStrLn =<< lines <$> hGetContents h -- Kim-Ee
participants (6)
-
Alexey Egorov
-
Ben
-
Christopher Allen
-
Kim-Ee Yeoh
-
MigMit
-
Will Yager