Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Specify list type for input

Tags:

haskell

I'm learning Haskell and I've decided to to the H-99 problem set. Naturally, I've become stuck on the first problem!

I have the following code:

module Main where

getLast [] = []
getLast x = x !! ((length x) - 1)

main = do 
    putStrLn "Enter a list:"
    x <- readLn
    print (getLast x)

Compiling this code gives the following error:

h-1.hs:8:14:
    No instance for (Read a0) arising from a use of `readLn'
    The type variable `a0' is ambiguous
    Possible fix: add a type signature that fixes these type variable(s)
    Note: there are several potential instances:
      instance Read () -- Defined in `GHC.Read'
      instance (Read a, Read b) => Read (a, b) -- Defined in `GHC.Read'
      instance (Read a, Read b, Read c) => Read (a, b, c)
        -- Defined in `GHC.Read'
      ...plus 25 others
    In a stmt of a 'do' block: x <- readLn
    In the expression:
      do { putStrLn "Enter a list:";
           x <- readLn;
           print (getLast x) }
    In an equation for `main':
        main
          = do { putStrLn "Enter a list:";
                 x <- readLn;
                 print (getLast x) }

h-1.hs:9:9:
    No instance for (Show a0) arising from a use of `print'
    The type variable `a0' is ambiguous
    Possible fix: add a type signature that fixes these type variable(s)
    Note: there are several potential instances:
      instance Show Double -- Defined in `GHC.Float'
      instance Show Float -- Defined in `GHC.Float'
      instance (Integral a, Show a) => Show (GHC.Real.Ratio a)
        -- Defined in `GHC.Real'
      ...plus 26 others
    In a stmt of a 'do' block: print (getLast x)
    In the expression:
      do { putStrLn "Enter a list:";
           x <- readLn;
           print (getLast x) }
    In an equation for `main':
        main
          = do { putStrLn "Enter a list:";
                 x <- readLn;
                 print (getLast x) }

That's a large error, but it seems to me that Haskell isn't sure what the input type will be. That's fine, and completely understandable. However, as this is supposed to work on a list of generics, I'm not sure how to specify that type. I tried this:

    x :: [a] <- readLn

...as [a] is the type that Haskell returns for an empty list (found with :t []). This won't compile either.

As I'm a beginner, I know there's a lot I'm missing, but in a basic sense - how can I satisfy Haskell's type system with input code? I'm a Haskell beginner looking for a beginner answer, if that's at all possible. (Also, note that I know there's a better way to do this problem (reverse, head) but this is the way I came up with first, and I'd like to see if I can make it work.)


1 Answers

You can't hope to write something like this which will detect the type of x at run time -- what kind of thing you're reading must be known at compile time. That's why @Sibi's answer uses [Int]. If it can't be deduced, you get a compile time error.

If you want a polymorphic read, you have to construct your own parser which lists the readable types.

maybeDo :: (Monad m) => Maybe a -> (a -> m b) -> m b
maybeDo f Nothing = return ()
maybeDo f (Just x) = f x

main = do
    str <- getLine
    maybeDo (maybeRead str :: Maybe Int) $ \i -> 
        putStrLn $ "Got an Int: " ++ show i
    maybeDo (maybeRead str :: Maybe String) $ \s ->
        putStrLn $ "Got a String: " ++ show s

There are lots of ways to factor out this repetition, but at some point you'll have to list all the types you'll accept.

(An easy way to see the problem is to define a new type MyInt which has the same Read instance as Int -- then how do we know whether read "42" should return an Int or a MyInt?)

like image 162
luqui Avatar answered Mar 10 '26 03:03

luqui



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!