实例化Haskell参数数据类型

时间:2014-10-16 12:27:14

标签: haskell

尝试掌握下面的Haskell type parameter

Prelude> data T a = C1 a | C2 (a -> a)

Prelude> :t C1 1
C1 1 :: Num a => T a

Prelude> :t C1 (+1)
C1 (+1) :: Num a => T (a -> a)

Prelude> :t C2 1
C2 1 :: Num (a -> a) => T a

Prelude> :t C2 (+1)
C2 (+1) :: Num a => T a

据我所知C1 1是不可能的,C2 1毫无意义,C1 (+1)C2 (+1)似乎是矛盾的。

为什么上述类型检查都没有抱怨?非常感谢您的启发。

2 个答案:

答案 0 :(得分:4)

在Haskell中,数字文字是多态的

1 :: Int
1 :: Integer
1 :: Double
...

从技术上讲,这是通用类型

获得的
1 :: Num a => a

所以," 1可以是任何类型,前提是此类型属于Num类"。

当您执行此操作时,例如,C2 11将被视为函数类型a -> a,并生成额外约束以确保a -> aNum

C2 1 :: Num (a -> a) => T a

当然,功能不是数字。那为什么没有类型错误?因为在Haskell中,不禁止扩展Num类以包含函数。你可以这样做, 例如:

instance Num b => Num (a -> b) where
   fromInteger n = \_ -> n
   x + y = \z -> x z + y z
   ...

有效地将1 :: a -> a转变为"常数"功能

这可以启用诸如(设计示例如下)

之类的代码
 case (some value of type T Int) of
 C1 x -> x
 C2 f -> (f + g) 50
 -- assumning g :: Int -> Int
 -- result is f 50 + g 50 

如果您不提供实例,那么代码本身并不是错误的,因为稍后可能会添加实例。在这种情况下,约束将在您的代码中保留,因为它无法释放。如果您尝试将T a转换为任何不涉及a的类型,则需要释放Num约束,此时编译器确实会抱怨。


可以通过注意到这是运算符部分来解释涉及(+1)的案例, 所以它不仅仅是1前面的一元加号。特别是,

(+1) means \x -> x + 1

所以(+1)实际上是继承函数。

答案 1 :(得分:1)

如果您希望出现错误,请创建一个情况,其中a必须相同,例如:

> :t [C1 (+1), C2(+1)]
Couldn't match expected type ....

在您的示例a中,a1a2不同。没有错误