Purescript将类视为循环类型同义词

时间:2019-05-12 06:53:50

标签: purescript

我正在尝试定义仅适用于类型级别自然数的实例。当我编译该文件时:

module Main where

data NatZero
data NatSucc n

class NatClass n where
   switch :: f NatZero -> (forall m. NatClass m => f (NatSucc m)) -> f n

它告诉我:

Error found:
at src/Main.purs:6:1 - 7:73 (line 6, column 1 - line 7, column 73)

  A cycle appears in the definition of type synonym NatClass
  Cycles are disallowed because they can lead to loops in the type checker.
  Consider using a 'newtype' instead.

为什么NatClass成为类型的同义词?我以为那是类型类。哪里有循环?为了使此功能像在Haskell中一样,我应该进行哪些更改?它告诉我要使用新类型,我应该怎样做?

2 个答案:

答案 0 :(得分:2)

该错误消息是令人误解的和不幸的-这不是您在此处的代码做错的任何事情,它的发生是由于编译器如何降低类类型的。

当前,字典将其表示为一条记录,因此此处错误中提到的同义词是因为编译器为该类创建了以下内容:

type NatClass n = 
  { switch :: forall f. f NatZero -> (forall m. NatClass m => f (NatSucc m)) -> f n }

以便它可以用字典参数相当直接地替换约束。

我认为现在此类(或任何将自身用作成员约束的类)将遇到相同的问题。

一段时间以来,我一直想更改类型类的表示形式,并为此使用一个WIP PR,我认为之后将允许这种事情。在此类之后,这些类将被简化为data类型而不是同义词,因此应允许引用。

答案 1 :(得分:0)

您可以通过自己具体化字典来轻松解决 Purescript 的限制。像 -

data NatZero
data NatSucc n

newtype NatClassDict n = NatClassDict (forall f. f NatZero -> (forall m. NatClass m => f (NatSucc m)) -> f n)

getSwitch :: NatClassDict n -> (forall f. f NatZero -> (forall m. NatClass m => f (NatSucc m)) -> f n)
getSwitch (NatClassDict f) = f

class NatClass n where
  natClassDict :: NatClassDict n

switch :: NatClass n => forall f. f NatZero -> (forall m. NatClass m => f (NatSucc m)) -> f n
switch = getSwitch natClassDict