[Haskell-beginners] More type errors I'm having trouble with

Dan Stromberg strombrg at gmail.com
Thu Dec 3 21:58:08 UTC 2015


I read somewhere (probably Learn You a Haskell or Real-World Haskell) that
beginners should use a lot of type declarations, but perhaps that's not a
great idea after all.

Here's dph.hs without the type declarations and some abuses of do cleaned
up:

import Md5s
import Split0
import System.IO

get_filenames :: String -> [String]
-- Let's hope this doesn't give locale-related roundtrip problems.
get_filenames buffer = Split0.split0 '\0' buffer

do_prefix_hash :: String -> (IO String, String)
do_prefix_hash filename = let hash = Md5s.prefix_md5 filename
                          in  (hash, filename)

tuple_to_string :: (String, String) -> String
tuple_to_string (first, second) = (show first) ++ " " ++ (show second)

main :: IO ()
main = do
    buffer <- (System.IO.hGetContents System.IO.stdin)
    let filenames = (get_filenames buffer)
    io_hash_tuples <- map do_prefix_hash filenames
    hash_tuples <- sequence io_hash_tuples
    let strings = map tuple_to_string hash_tuples
    mapM_ putStrLn strings

The (far fewer) errors I get now are:
dph.hs:21:23:
    Couldn't match type `[]' with `IO'
    Expected type: IO (IO String, String)
      Actual type: [(IO String, String)]
    In the return type of a call of `map'
    In a stmt of a 'do' block:
      io_hash_tuples <- map do_prefix_hash filenames
    In the expression:
      do { buffer <- (hGetContents stdin);
           let filenames = (get_filenames buffer);
           io_hash_tuples <- map do_prefix_hash filenames;
           hash_tuples <- sequence io_hash_tuples;
           .... }

dph.hs:22:29:
    Couldn't match expected type `[IO (String, String)]'
                with actual type `(IO String, String)'
    In the first argument of `sequence', namely `io_hash_tuples'
    In a stmt of a 'do' block: hash_tuples <- sequence io_hash_tuples
    In the expression:
      do { buffer <- (hGetContents stdin);
           let filenames = (get_filenames buffer);
           io_hash_tuples <- map do_prefix_hash filenames;
           hash_tuples <- sequence io_hash_tuples;
           .... }

I'm continuing to study Learn You a Haskell, though I'd kinda like to
continue coding on this project in parallel.

On Tue, Dec 1, 2015 at 7:47 PM, Simon Jakobi <simon.jakobi at googlemail.com>
wrote:

> Hi Dan,
>
> I'm having a hard time understanding those error messages too. It
> seems to me that part of the problem is that GHC is confused by some
> incorrect type annotations of yours.
>
> I suggest that you delete or at least comment out your own type
> annotations and then either work with the hopefully simpler error-messages
> from GHC or use the `:load` and `:type` commands in ghci to discover
> the inferred
> types for your functions.
>
> Depending on how close the inferred type is to the intended type, you
> may have to adjust the definitions.
>
> Also note that you sometimes incorrectly and unnecessarily use
> do-notation in "non-monadic"/plain functions, for example in
> tuple_to_string and get_filenames.
>
> You could also consider following a book or a course until you feel
> more comfortable trying things on your own:
> Take a look at learnyouahaskell.com or github.com/bitemyapp/learnhaskell.
>
> Good luck!
> Simon
>
> 2015-12-02 1:12 GMT+01:00, Dan Stromberg <strombrg at gmail.com>:
> > I'm continuing my now-and-then exploration of Haskell.
> >
> > I'm getting a new crop of type errors that I'm pulling my hair out over.
> >
> > The errors I'm getting are:
> >
> > $ make
> > below cmd output started 2015 Tue Dec 01 04:05:17 PM PST
> > # --make will go out and find what to build
> > ghc -Wall --make -o dph dph.hs Split0.hs
> > [1 of 3] Compiling Split0           ( Split0.hs, Split0.o )
> > [2 of 3] Compiling Md5s             ( Md5s.hs, Md5s.o )
> > [3 of 3] Compiling Main             ( dph.hs, dph.o )
> >
> > dph.hs:13:13:
> >     Couldn't match type `IO' with `(,) (IO String)'
> >     Expected type: (IO String, String)
> >       Actual type: IO String
> >     In a stmt of a 'do' block: hash <- prefix_md5 filename :: IO String
> >     In the expression:
> >       do { hash <- prefix_md5 filename :: IO String;
> >            (hash, filename) }
> >     In an equation for `do_prefix_hash':
> >         do_prefix_hash filename
> >           = do { hash <- prefix_md5 filename :: IO String;
> >                  (hash, filename) }
> >
> > dph.hs:14:6:
> >     Couldn't match type `[Char]' with `IO String'
> >     Expected type: IO String
> >       Actual type: String
> >     In the expression: hash
> >     In a stmt of a 'do' block: (hash, filename)
> >     In the expression:
> >       do { hash <- prefix_md5 filename :: IO String;
> >            (hash, filename) }
> >
> > dph.hs:24:23:
> >     Couldn't match type `[]' with `IO'
> >     Expected type: IO (IO String, String)
> >       Actual type: [(IO String, String)]
> >     In a stmt of a 'do' block:
> >       io_hash_tuples <- map do_prefix_hash filenames ::
> >                           [(IO String, String)]
> >     In the expression:
> >       do { buffer <- (hGetContents stdin) :: IO String;
> >            let filenames = ...;
> >            io_hash_tuples <- map do_prefix_hash filenames ::
> >                                [(IO String, String)];
> >            hash_tuples <- sequence io_hash_tuples :: [(String, String)];
> >            .... }
> >     In an equation for `main':
> >         main
> >           = do { buffer <- (hGetContents stdin) :: IO String;
> >                  let filenames = ...;
> >                  io_hash_tuples <- map do_prefix_hash filenames ::
> >                                      [(IO String, String)];
> >                  .... }
> >
> > dph.hs:25:20:
> >     Couldn't match type `[a0]' with `(String, String)'
> >     Expected type: [(String, String)]
> >       Actual type: [[a0]]
> >     In the return type of a call of `sequence'
> >     In a stmt of a 'do' block:
> >       hash_tuples <- sequence io_hash_tuples :: [(String, String)]
> >     In the expression:
> >       do { buffer <- (hGetContents stdin) :: IO String;
> >            let filenames = ...;
> >            io_hash_tuples <- map do_prefix_hash filenames ::
> >                                [(IO String, String)];
> >            hash_tuples <- sequence io_hash_tuples :: [(String, String)];
> >            .... }
> >
> > dph.hs:25:20:
> >     Couldn't match type `[]' with `IO'
> >     Expected type: IO (String, String)
> >       Actual type: [(String, String)]
> >     In a stmt of a 'do' block:
> >       hash_tuples <- sequence io_hash_tuples :: [(String, String)]
> >     In the expression:
> >       do { buffer <- (hGetContents stdin) :: IO String;
> >            let filenames = ...;
> >            io_hash_tuples <- map do_prefix_hash filenames ::
> >                                [(IO String, String)];
> >            hash_tuples <- sequence io_hash_tuples :: [(String, String)];
> >            .... }
> >     In an equation for `main':
> >         main
> >           = do { buffer <- (hGetContents stdin) :: IO String;
> >                  let filenames = ...;
> >                  io_hash_tuples <- map do_prefix_hash filenames ::
> >                                      [(IO String, String)];
> >                  .... }
> >
> > dph.hs:25:29:
> >     Couldn't match expected type `[[a0]]'
> >                 with actual type `(IO String, String)'
> >     In the first argument of `sequence', namely `io_hash_tuples'
> >     In a stmt of a 'do' block:
> >       hash_tuples <- sequence io_hash_tuples :: [(String, String)]
> >     In the expression:
> >       do { buffer <- (hGetContents stdin) :: IO String;
> >            let filenames = ...;
> >            io_hash_tuples <- map do_prefix_hash filenames ::
> >                                [(IO String, String)];
> >            hash_tuples <- sequence io_hash_tuples :: [(String, String)];
> >            .... }
> >
> > dph.hs:26:39:
> >     Couldn't match expected type `[(String, String)]'
> >                 with actual type `(String, String)'
> >     In the second argument of `map', namely `hash_tuples'
> >     In the expression: map tuple_to_string hash_tuples :: [String]
> >     In an equation for `strings':
> >         strings = map tuple_to_string hash_tuples :: [String]
> > make: *** [dph] Error 1
> > above cmd output done    2015 Tue Dec 01 04:05:18 PM PST
> >
> >
> > dph.hs looks like:
> > import Md5s
> > import Split0
> > import System.IO
> >
> > get_filenames :: String -> [String]
> > get_filenames buffer = do
> >     -- Let's hope this doesn't give locale-related roundtrip problems.
> >     Split0.split0 '\0' buffer :: [String]
> >
> > do_prefix_hash :: String -> (IO String, String)
> > do_prefix_hash filename = do
> >     hash <- Md5s.prefix_md5 filename :: (IO String)
> >     (hash, filename)
> >
> > tuple_to_string :: (String, String) -> String
> > tuple_to_string (first, second) = do
> >     (show first) ++ " " ++ (show second)
> >
> > main :: IO ()
> > main = do
> >     buffer <- (System.IO.hGetContents System.IO.stdin) :: IO String
> >     let filenames = (get_filenames buffer) :: [String]
> >     io_hash_tuples <- map do_prefix_hash filenames :: [(IO String,
> String)]
> >     hash_tuples <- sequence io_hash_tuples :: [(String, String)]
> >     let strings = map tuple_to_string hash_tuples :: [String]
> >     mapM_ putStrLn strings
> >
> >
> > And Md5s.hs looks like:
> > module Md5s where
> >
> > import qualified System.IO
> > import qualified Text.Printf
> > -- cabal install cryptohash
> > import qualified Crypto.Hash.MD5
> > import qualified Data.ByteString
> > import qualified Data.ByteString.Lazy
> >
> > --
> >
> http://stackoverflow.com/questions/10099921/efficiently-turn-a-bytestring-into-a-hex-representation
> > byte_string_to_hex :: Data.ByteString.ByteString -> String
> > byte_string_to_hex = concatMap (Text.Printf.printf "%02x") .
> > Data.ByteString.unpack
> >
> > prefix_md5 :: String -> IO String
> > prefix_md5 filename = do
> >     let prefix_length = 1024
> >     file <- System.IO.openBinaryFile filename System.IO.ReadMode :: IO
> > System.IO.Handle
> >     data_read <- Data.ByteString.hGet file prefix_length :: IO
> > Data.ByteString.ByteString
> >     _ <- System.IO.hClose file
> >     let hasher = Crypto.Hash.MD5.init :: Crypto.Hash.MD5.Ctx
> >     let hasher2 = Crypto.Hash.MD5.update hasher data_read ::
> > Crypto.Hash.MD5.Ctx
> >     let binary_digest = Crypto.Hash.MD5.finalize hasher2 ::
> > Data.ByteString.ByteString
> >     let hex_digest = byte_string_to_hex binary_digest :: String
> >     return hex_digest :: IO String
> >
> > full_md5 :: String -> IO String
> > full_md5 filename = do
> >     file <- System.IO.openBinaryFile filename System.IO.ReadMode :: IO
> > System.IO.Handle
> >     data_read <- Data.ByteString.Lazy.hGetContents file :: IO
> > Data.ByteString.Lazy.ByteString
> >     let binary_digest = Crypto.Hash.MD5.hashlazy data_read ::
> > Data.ByteString.ByteString
> >     let hex_digest = byte_string_to_hex binary_digest :: String
> >     -- Does this get closed for us later?
> >     -- strace shows the file getting closed without our explicit close.
> >     -- _ <- System.IO.hClose file
> >     return hex_digest :: IO String
> >
> >
> > It might be easier to view these at
> >
> http://stromberg.dnsalias.org/svn/equivalence-classes/trunk/equivs3-haskell/
> > , so the line numbers are precise.
> >
> > What is the deal?
> >
> > Can anyone tell me what should be running through my head to fix this
> kind
> > of problem on my own in the future?
> >
> > Thanks!
> >
> > --
> > Dan Stromberg
> >
> _______________________________________________
> Beginners mailing list
> Beginners at haskell.org
> http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners
>



-- 
Dan Stromberg
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.haskell.org/pipermail/beginners/attachments/20151203/e23a4e08/attachment-0001.html>


More information about the Beginners mailing list