函数中的各种类型

时间:2013-05-03 12:36:45

标签: haskell

请使用以下代码:

{-# LANGUAGE KindSignatures, DataKinds #-}

data Nat = O | S Nat

class NatToInt (n :: Nat) where
    natToInt :: n -> Int

instance NatToInt O where
    natToInt _ = 0

instance (NatToInt n) => NatToInt (S n) where
    natToInt _ = 1 + natToInt (undefined :: n)

GHC通知我们,它期望OpenKind的类型规范中的natToInt而不是Nat,因此拒绝编译。这可以通过某种铸造来解决:

data NatToOpen :: Nat -> *

然后将n替换为NatToOpen n - s中的natToInt

问题1:有没有办法在不使用类型级包装器的情况下在任何函数中指定*以外的类型?

问题2:在我看来,非类函数将很乐意使用任何类型的类型,例如:

foo :: (a :: *) -> (a :: *)
foo = id

bar = foo (S O)

但是在内部类中,编译器会抱怨类型不匹配,如上所述。这是为什么?似乎非类函数在各种类型中都是正确的多态,因为上面我实际上指定了 *,它仍然适用于Nat - s,就好像种类被简单地忽略了。

1 个答案:

答案 0 :(得分:6)

值总是有类型*(可能有一些涉及拆箱的奇怪异常?),所以没有什么可以将函数应用于或作为其他类型的参数。

在最后一个示例中,您将foo应用于Nat的未提升版本:值为SO,其类型< / em>是Nat,其类型为*。在类定义中,您使用签名提供Nat种类,这意味着提升版本,其中SO类型

NatToOpen类型只是以通常的方式使用幻像类型,但使用非*类型的幻像类型参数。

这种区别对DataKinds也不是新的。例如,没有类型为Maybe :: * -> *的值,与类型forall a. Maybe a :: *不同,后者是Nothing的类型。