为什么ghci desugar类型列表和类型族?可以有选择地禁用它吗?


93

我试图使我的库的ghci显示类型尽可能直观,但是在使用更高级的类型功能时遇到了很多困难。

假设我在文件中有以下代码:

{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeOperators #-}

import GHC.TypeLits

data Container (xs::[*]) = Container

我将其加载到ghci中,然后键入以下命令:

ghci> :t undefined :: Container '[String,String,String,String,String]

不幸的是,ghci给了我一个难看的外观:

:: Container
       ((':)
          *
          String
          ((':)
             * String ((':) * String ((':) * String ((':) * String ('[] *))))))

ghci删除了用于类型级别字符串的糖。有什么方法可以防止ghci这样做并给我漂亮的版本吗?


在相关说明中,可以说我创建了一个类型级别的Replicate函数

data Nat1 = Zero | Succ Nat1

type family Replicate (n::Nat1) x :: [*]
type instance Replicate Zero x = '[]
type instance Replicate (Succ n) x = x ': (Replicate n x)

type LotsOfStrings = Replicate (Succ (Succ (Succ (Succ (Succ Zero))))) String

现在,当我要求ghci使用LotsOfStrings以下类型时:

ghci> :t undefined :: Container LotsOfStrings

ghci很好,给了我漂亮的结果:

undefined :: Container LotsOfStrings

但是如果我要求Replicated版本,

ghci> :t undefined :: Container (Replicate (Succ (Succ (Succ (Succ (Succ Zero))))) String)

当ghci不能代替类型同义词时,它会代替类型家族:

:: Container
       ((':)
          *
          [Char]
          ((':)
             * [Char] ((':) * [Char] ((':) * [Char] ((':) * [Char] ('[] *))))))

ghci为什么要替代类型族而不是类型同义词?有什么方法可以控制ghci何时进行替换?


7
因为类型同义词是专门为人类使用而设计的-它不会进行替换,因为它承认您是因为要以这种方式编写/查看类型而创建了类型同义词。它用类型族代替,因为类型族实际上是关于计算/推导类型,而不是显示它。
AndrewC

解决问题的方法就在您的问题中-如果要缩写,请键入同义词。
AndrewC

2
@AndrewC我刚刚想到了另一个与您的评论有关的问题:为什么有时将String类型显示为[Char],有时将String 显示为String
Mike Izbicki

1
认为 ghci会尝试保留在源代码中找到的类型同义词。也就是说,如果一个函数被声明为type String->String,则其结果的类型将显示为String。但是,如果必须从片段中构造类型,例如"abc"(与相同'a':'b':'c':[]),则无需保留同义词。这纯粹是猜测。
n。代词

4
@nm:请注意,当更多的通用推断类型与更少的通用,显式命名的类型变量结合在一起时,GHC会进行类似的尝试来保留类型变量的名称。我怀疑如果显式类型String与类型变量f a或统一[a],则[Char]出于类似原因,它将在以后显示。
CA McCann

Answers:


2

我知道的解决方法是使用:kind。例如,

ghci>:kind(容器'[[String,String,String,String,String]]

给出:

(容器'[[String,String,String,String,String]):: *

ghci>:种!(容器'[String,String,String,String,String])

将打印如下内容:

容器

((':)

  *
  [Char]
  ((':)
     * [Char] ((':) * [Char] ((':) * [Char] ((':) * [Char] ('[] *))))))

当然,正式地,您要向ghci问一个不同的问题kind,但这是可行的。undefined ::无论如何,使用都是一种解决方法,所以我认为这足够了。


我只是undefined ::用来举一个简单的例子。真正的问题是,当您收到一条错误消息时,该错误消息具有一千种不同类型的列表。打印它需要占用页面,并且很难解析。
Mike Izbicki

是的,足够公平。可能已经意识到了。我欠您一个更好的答案
user2141650

2

即将发布的GHC 7.8中已修复此问题。

如果数据类型使用PolyKinds,则GHC 7.6可打印种类。所以你看到(':) * String ('[] *)的不仅仅是(':) String '[]

在GHC 7.8中,默认情况下不再显示种类,并且您的数据类型也像您期望的那样漂亮地打印为列表。您可以使用new标志-fprint-explicit-kinds查看GHC 7.6中的显式种类。我不知道这样做的原因,大概是明确的种类旨在帮助理解PolyKinds。


0
import GHC.TypeLits

data Container (xs::[*]) = Container

我将其加载到ghci中,然后键入以下命令:

:t undefined :: Container '[String,String,String,String,String]

所以...?我认为您仍然可以将结果重新计算,即String ((':) * String ((':) * String ((':) * ...
左右左转
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.