指定输入的列表类型

时间:2014-04-19 00:58:48

标签: haskell

我正在学习Haskell,我决定使用H-99问题集。当然,我已经陷入了第一个问题!

我有以下代码:

module Main where

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

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

编译此代码会出现以下错误:

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) }

这是一个很大的错误,但在我看来,Haskell不确定输入类型是什么。这很好,完全可以理解。但是,因为这应该在泛型列表上工作,我不知道如何指定该类型。我试过这个:

    x :: [a] <- readLn

...因为[a]是Haskell为空列表返回的类型(与:t []一起找到)。这也不会编译。

由于我是初学者,我知道有很多我不知道,但从基本的意义上讲 - 我如何用输入代码满足Haskell的类型系统?我是一名Haskell初学者,正在寻找初学者的答案,如果可能的话。 (另外,请注意我知道有更好的方法来解决这个问题(反向,头部),但这是我首先提出的方式,我想看看我是否可以使它工作。)

2 个答案:

答案 0 :(得分:2)

你不能希望写一些这样的东西,它会在运行时检测x的类型 - 你必须在编译时知道你read什么样的东西。这就是@ Sibi的答案使用[Int]的原因。如果无法推断,则会出现编译时错误。

如果要进行多态读取,则必须构建自己的解析器,列出可读类型。

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

有很多方法可以分解这种重复,但在某些时候你必须列出你接受的所有类型。

(查看问题的一种简单方法是定义一个与MyInt具有相同Read实例的新类型Int - 然后我们如何知道{{1}应该返回read "42"Int?)

答案 1 :(得分:1)

这应该有效:

getLast :: Num a => [a] -> a
getLast [] = 0
getLast x = x !! ((length x) - 1)

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

为什么为空列表返回0而不是空列表?

因为它没有成功。因为您为空列表返回[],而对于其他情况,您将返回列表中的元素,即a。现在由于a类型不等于list,因此它不会成为类型检查。更好的设计是使用Maybe数据类型捕获此类情况。

此外,由于返回0,上述函数仅适用于为其创建Num个实例的类型列表。您可以使用error函数来缓解该问题。

  

但是,这应该适用于通用列表,而不仅仅是Ints列表   或数字,对吧?

是的,它应该适用于多态列表。你可以创建一个像getLast这样的函数,它可以用于所有类型的List。但是当你想从用户那里获得输入时,它应该知道你给出的输入类型。因为类型检查器无法知道您是将其视为Int of List还是Double of List等。