什么时候Haskell需要类型签名?

时间:2014-11-21 18:28:33

标签: haskell types typeclass

许多介绍性文本会告诉您,在Haskell类型中,签名“几乎总是”可选的。任何人都可以量化“差不多”的部分吗?

据我所知,时间需要显式签名是消除类型类的歧义。 (规范的例子是read . show。)还有其他我没有想过的情况,或者是这样吗?

(我知道如果你超越Haskell 2010就有很多例外。例如,GHC永远不会推断排名N类型。但是排名N类型是语言扩展,不是官方标准的一部分[然而]。)

3 个答案:

答案 0 :(得分:25)

一般来说,多态递归需要类型注释。

f :: (a -> a) -> (a -> b) -> Int -> a -> b
f f1 g n x = 
    if n == (0 :: Int)
    then g x
    else f f1 (\z h -> g (h z)) (n-1) x f1

(图片来源:Patrick Cousot)

注意递归调用如何看起来很糟糕(!):它使用五个参数调用自身,尽管f只有四个!然后记住b可以用c -> d实例化,这会导致出现额外的参数。

以上设计的例子计算

f f1 g n x = g (f1 (f1 (f1 ... (f1 x))))

f1n次。当然,有一种更简单的方法来编写一个等效的程序。

答案 1 :(得分:20)

单态限制

如果您启用了MonomorphismRestriction,那么有时您需要添加类型签名以获得最常规的类型:

{-# LANGUAGE MonomorphismRestriction #-}
-- myPrint :: Show a => a -> IO ()
myPrint = print
main = do
  myPrint ()
  myPrint "hello"

这将失败,因为myPrint是单态的。您需要取消注释类型签名才能使其正常工作,或者禁用MonomorphismRestriction

幻影约束

当您将带有约束的多态值放入元组时,元组本身变为多态并具有相同的约束:

myValue :: Read a => a
myValue = read "0"

myTuple :: Read a => (a, String)
myTuple = (myValue, "hello")

我们知道约束会影响元组的第一部分,但会影响第二部分。不幸的是,类型系统并不知道如果您尝试这样做会抱怨:

myString = snd myTuple

即使直觉上人们希望myString只是String,但类型检查器需要来专门化类型变量a并确定是否约束实际上是满足的。为了使此表达式起作用,需要注释sndmyTuple的类型:

myString = snd (myTuple :: ((), String))

答案 2 :(得分:4)

在Haskell中,我确定你知道,类型是推断的。换句话说,编译器会计算出你想要的类型。

但是,在Haskell中,还有多态类型类,其函数根据返回类型以不同的方式起作用。这是Monad课程的一个例子,虽然我没有定义所有内容:

class Monad m where
    return :: a -> m a
    (>>=) :: m a -> (a -> m b) -> m b
    fail :: String -> m a

我们只提供了类型签名的许多功能。我们的工作是为可以视为Monad的不同类型制作实例声明,例如Maybe t[t]

看看这段代码 - 它不会以我们预期的方式工作:

return 7

这是Monad课程的一个功能,但由于有多个Monad,我们必须指定我们想要的返回值/类型,否则它会自动成为IO Monad。所以:

return 7 :: Maybe Int
-- Will return...
Just 7

return 6 :: [Int]
-- Will return...
[6]

这是因为[t]Maybe都已在Monad类型类中定义。

这是另一个例子,这次来自随机类型类。此代码抛出错误:

random (mkStdGen 100)

由于random会在Random类中返回某些内容,因此我们必须使用StdGen对象tupelo定义我们想要返回的类型,并使用我们想要的任何值:

random (mkStdGen 100) :: (Int, StdGen)
-- Returns...
(-3650871090684229393,693699796 2103410263)

random (mkStdGen 100) :: (Bool, StdGen)
-- Returns...
(True,4041414 40692)

这一切都可以在learn you a Haskell在线找到,但您必须做一些长时间的阅读。这个,我几乎100%肯定,它是唯一需要类型的时候。