5

我正在尝试编写一个返回列表中第一项的 Haskell 函数。

h [] = Nothing
h (x:xs) = x

当我用空列表调用它时:

main = print (h [])

我收到以下错误:

prog.hs:4:8:
    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 23 others
    In the expression: print (h [])
    In an equation for `main': main = print (h [])

当我为函数提供空列表时,我希望结果为Nothing 。

4

2 回答 2

16

这里有几个问题,我们先添加一个合理的类型签名

h :: [a] -> Maybe a
h [] = Nothing
h (x:xs) = x

现在我们得到一个错误,我们返回一个 plainx所以x需要是 type Maybe a。我们可能不想要这个,所以我们将它包装在Just构造函数中

h (x:_) = Just x

现在谈谈你的问题。

请注意,这不是特定于您的功能,结果

main = print $ head []
main = print $ id []
main = print $ tail []

都是一样的。

的类型[][a]。由于我们没有指定a类型h []是什么Show a => Maybe a。额外的Show进来是因为我们想打印我们的结果。但我们实际上并没有说是什么a让 GHC 吓坏了,无法默认它。

有两种方法可以修复它,愚蠢的方法是使h单态(monomorphisize?)h

h :: [Int] -> Maybe Int -- Bad

更聪明的方法是在我们的呼叫站点简单地选择一个具体类型。

main = print $ h ([] :: [Int])

我选择Int没有特别的原因,没那么重要。现在Maybe Int是可打印的,所以我们都准备好了。语法与顶级组件的::语法相同,只是[]在我们的表达式中声明类型为[Int].

有趣的事实是,GHCi 的违约行为比 GHC 更激进。这意味着

 main = print []

在 GHCi 中是合法的,但在 GHC 中不合法。如果您遇到有趣的行为,请询问表达式的类型以查看默认值是什么

 :t []
于 2013-09-17T19:55:59.397 回答
1

编译器吃掉你的函数

h [] = Nothing
h (x:xs) = x

h有类型[Maybe a] -> Maybe a,没有[a] -> Maybe a

h :: [a] -> Maybe a
h [] = Nothing
h (x:_) = Just x

[]是多态类型[a],所以函数 result h [], equalsNothig仍然是多态类型Maybe a,但print不能与多态类型一起使用(如果我们没有 的实例Show)。在 gchi 你可以运行

> print (h [])

但是这种情况下 gchi 会将其转换为print ((h []) :: Maybe Int)

但是,如果您的多态函数较少,例如:

h [] = Nothing
h (x:_) = Just $ x == ""

然后编译器找到它的类型h :: [String] -> Maybe Boolprint (h [])工作!

于 2013-09-18T13:09:47.413 回答