
I found this code on the net somewhere. It compiles and works properly: import qualified Data.ByteString as BS import Text.Printf (printf) toHex :: BS.ByteString -> String toHex bytes = do hex <- BS.unpack bytes printf "%02x" hex I cannot understand the 'do' notation is required, because it seems to be a pure function. I guess there's a monad hiding somewhere that my newbie mind can't see. So, I rewrote the code to remove the 'do stuff': -- BAD import qualified Data.ByteString as BS import Text.Printf (printf) toHex :: BS.ByteString -> String toHex bytes = printf "02x" (BS.unpack bytes) WRONG. Ghci says: xx2.hs:5:15: error: • No instance for (Text.Printf.IsChar GHC.Word.Word8) arising from a use of ‘printf’ • In the expression: printf "02x" (BS.unpack bytes) In an equation for ‘toHex’: toHex bytes = printf "02x" (BS.unpack bytes) | 5 | toHex bytes = printf "02x" (BS.unpack bytes) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Can someone please explain to me: 1. Why does this simple-looking code to convert a bytestring to a string of hex characters require 'do' or equivalent code? 2. What is the specific problem with my version of the code. The error message doesn't mean much to me yet.

Hello Terry On Sun, Jul 07, 2019 at 11:24:47AM -0400, Terry Phelps wrote:
I found this code on the net somewhere. It compiles and works properly:
import qualified Data.ByteString as BS import Text.Printf (printf) toHex :: BS.ByteString -> String toHex bytes = do hex <- BS.unpack bytes printf "%02x" hex
I cannot understand the 'do' notation is required, because it seems to be a pure function. I guess there's a monad hiding somewhere that my newbie mind can't see.
`toHex` is pure (non IO), but it has an /effect/. In this case, it takes advantage of the list monad to achieve non-determinism. Specifically, since unpack :: ByteString -> [Word8] printf (which in our case has signature (`String -> Char`) gets called on each of those [Word8]. The result will obviously be [Char], which `String` is an alias of.
So, I rewrote the code to remove the 'do stuff':
[...] toHex :: BS.ByteString -> String toHex bytes = printf "02x" (BS.unpack bytes)
A do-less version still is /monadic/, hence it will have >>= or >> or similar somewhere. This works: toHex2 :: BS.ByteString -> String toHex2 bytes = BS.unpack bytes >>= printf "%02x" and follows the reasoning above (feed every every Word8 to `printf "%02x"`). Does this answer your questions? -F

I have written enough code in the IO monad to fairly well understand how
the 'do' and 'bind' forms work. But I've never seen monadic code that was
NOT in the IO monad. Your explanation tells me where to go do more study.
Thank you.If I go read the definition of bind in the List monad, it will
probably become clear. In the original code, the List monad is completely
invisible to my untrained eye, and I was confused.
On Sun, Jul 7, 2019 at 12:13 PM Francesco Ariis
Hello Terry
On Sun, Jul 07, 2019 at 11:24:47AM -0400, Terry Phelps wrote:
I found this code on the net somewhere. It compiles and works properly:
import qualified Data.ByteString as BS import Text.Printf (printf) toHex :: BS.ByteString -> String toHex bytes = do hex <- BS.unpack bytes printf "%02x" hex
I cannot understand the 'do' notation is required, because it seems to be a pure function. I guess there's a monad hiding somewhere that my newbie mind can't see.
`toHex` is pure (non IO), but it has an /effect/. In this case, it takes advantage of the list monad to achieve non-determinism.
Specifically, since
unpack :: ByteString -> [Word8]
printf (which in our case has signature (`String -> Char`) gets called on each of those [Word8]. The result will obviously be [Char], which `String` is an alias of.
So, I rewrote the code to remove the 'do stuff':
[...] toHex :: BS.ByteString -> String toHex bytes = printf "02x" (BS.unpack bytes)
A do-less version still is /monadic/, hence it will have >>= or >> or similar somewhere. This works:
toHex2 :: BS.ByteString -> String toHex2 bytes = BS.unpack bytes >>= printf "%02x"
and follows the reasoning above (feed every every Word8 to `printf "%02x"`).
Does this answer your questions? -F
_______________________________________________ Beginners mailing list Beginners@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners

It's more correct to say the List Monad Is a Monad instance who is a List But people look at you funny In my case Funnier than usual

It's more correct to say the
List Monad
Is a
Monad instance who is a List
But people look at you funny
In my case
Funnier than usual
On Sun., Jul. 7, 2019, 9:47 a.m. Terry Phelps,
I have written enough code in the IO monad to fairly well understand how the 'do' and 'bind' forms work. But I've never seen monadic code that was NOT in the IO monad. Your explanation tells me where to go do more study. Thank you.If I go read the definition of bind in the List monad, it will probably become clear. In the original code, the List monad is completely invisible to my untrained eye, and I was confused.
On Sun, Jul 7, 2019 at 12:13 PM Francesco Ariis
wrote: Hello Terry
On Sun, Jul 07, 2019 at 11:24:47AM -0400, Terry Phelps wrote:
I found this code on the net somewhere. It compiles and works properly:
import qualified Data.ByteString as BS import Text.Printf (printf) toHex :: BS.ByteString -> String toHex bytes = do hex <- BS.unpack bytes printf "%02x" hex
I cannot understand the 'do' notation is required, because it seems to be a pure function. I guess there's a monad hiding somewhere that my newbie mind can't see.
`toHex` is pure (non IO), but it has an /effect/. In this case, it takes advantage of the list monad to achieve non-determinism.
Specifically, since
unpack :: ByteString -> [Word8]
printf (which in our case has signature (`String -> Char`) gets called on each of those [Word8]. The result will obviously be [Char], which `String` is an alias of.
So, I rewrote the code to remove the 'do stuff':
[...] toHex :: BS.ByteString -> String toHex bytes = printf "02x" (BS.unpack bytes)
A do-less version still is /monadic/, hence it will have >>= or >> or similar somewhere. This works:
toHex2 :: BS.ByteString -> String toHex2 bytes = BS.unpack bytes >>= printf "%02x"
and follows the reasoning above (feed every every Word8 to `printf "%02x"`).
Does this answer your questions? -F
_______________________________________________ Beginners mailing list Beginners@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners
_______________________________________________ Beginners mailing list Beginners@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners
participants (3)
-
Francesco Ariis
-
KC
-
Terry Phelps