如何在haskell中创建类的类型实例?

时间:2016-07-30 16:11:10

标签: haskell types church-encoding

我是Haskell的新手。

我正在寻找是否有办法创建类的实例。

有没有办法让这段代码在不使用数据或newtype的情况下工作?

type N = ∀n. (n -> n) -> n -> n

instance Printable N where
        print :: N -> IO ()
        read  :: String -> N 

当我尝试在GHCi中加载模块时,它告诉我:

Illegal polymorphic or qualified type: N
In the instance declaration for ‘Printable N’

1 个答案:

答案 0 :(得分:5)

你在那里写的内容看起来很像类声明,而不是实例。也许你的意思是这个?

class Printable n where
  print :: n -> IO ()
  read  :: String -> n

请注意,n必须是小写的,因为这是类型变量,您正在量化该类。如果你真的想要定义一个实例,那么你,{em>实例化 nN

instance Printable N where
  print n = ...
  read str = ...

此时类型签名都是固定的(来自类定义),您需要编写的是这些函数的实际绑定,因此它必须是=,而不是::

问题是:为什么你还需要自己的班级?它只会导致与前奏中已有的标准函数printread发生名称冲突。你实际应该做的是使用你的N类型实例化那些标准类,即

instance Show N where
  show n = ...
instance Read N where
  readsPrec _ str = ...

那就是说,为了得到你问的实际问题: no ,不可能为像{{1}这样的多态类型明智地定义任何实例}}。如何将编译器与更具体的类型(如∀ n . (n->n) -> n->n)或更常见的类型(如(Int->Int) -> Int->Int)区分开来?这很无望。 正确的要做的就是将其包装成newtype;它隐藏了通用量化,并允许编译器正确区分∀ n m . (n->m) -> n->m与其他类型。

或者,您可以直接编写接受/生成N单态函数

N

实际上后者对于类型系统已经太多了:showChurch :: N -> String showChurch n = ... readsPrecChurch :: Int -> ReadS N readsPrecChurch _ str = ...

的缩写
ReadS N

列表中的通用量化?哦,哦。这是一种不可预测的类型。 GHC确实有readsPrecChurch :: Int -> String -> [(∀ n . (n->n) -> n->n, String)] 扩展名,但它确实没有用。

同样,通过不公开使用多态类型来避免这些问题。 Rank-N类型(特别是镜头)有一些很好的用途,但大多数时候它们完全是过度杀伤和不必要的。实际上,使用像这样的教堂数字肯定没有充分的理由。

-XImpredicativeTypes

将允许您毫无问题地定义任意实例或函数。而且,实际上,只是做

newtype N = Church { getChurch :: ∀ n . (n->n) -> n->n }

对于整数来说,所有标准实例当然都一样好......