Haskell 漂亮打印机类实例的绑定

Haskell 漂亮打印机类实例的绑定,haskell,Haskell,如何为以下实例创建绑定?在这一点上,我正在寻找任何可以编译的绑定解决方案,以便开始理解我的错误。我的全部代码是: {-# OPTIONS_GHC -Wall #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeOperators #-} {-# LANGUAGE ConstrainedClassMethods #-} {-# LANGUAGE InstanceSigs #-} module Tagless where import Data.

如何为以下实例创建绑定?在这一点上,我正在寻找任何可以编译的绑定解决方案,以便开始理解我的错误。我的全部代码是:

{-# OPTIONS_GHC -Wall #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE ConstrainedClassMethods #-}
{-# LANGUAGE InstanceSigs #-}

module Tagless where

import Data.Text.IO as T
import Data.Text.Prettyprint.Doc.Render.Text 
 
data Exp = B Bool 
    | MyInt Int 
    
data Doc ann 
 
class Pretty a where
    pretty :: Show a => a -> Doc ann 
    prettyList :: [a] -> Doc ann 
    
instance Pretty Bool where
    pretty :: Bool -> Doc ann
    prettyList :: [Bool] -> Doc ann
我尝试了以下几种类型和变体,但得到了多个不匹配的类型。1) 既然B是Bool Exp,为什么不能使用它呢?2) 如何创建与文档匹配的绑定

instance Pretty Bool where
    pretty :: Bool -> Doc ann
    prettyList :: [Bool] -> Doc ann
    pretty (B e1) = e1 
    prettyList [B e1] = e1

我正在使用package

您正在重新定义
Doc
类型和
Pretty
类,因此首先您应该删除
数据
定义,并使用从
数据.Text.Prettyprint.Doc
导入的定义(或者在库的较新版本中使用
Prettyprinter
)。接下来,您要为
Exp
创建
实例
,而当前您正在为
Bool
编写一个实例(该实例已经存在):

通过对
Exp
类型进行模式匹配,并为每个构造函数定义所需的漂亮打印,可以定义
pretty
。例如,如果您只想显示布尔数和整数及其默认的
Pretty
实例,只需对从
Exp
提取的值调用
Pretty

    pretty exp = case exp of
        B bool -> pretty bool    -- (1) 
        MyInt int -> pretty int  -- (2)
请注意,(1)和(2)处对
pretty
的调用是不同的实例:第一个是
pretty::Bool->Doc ann
,第二个是
pretty::Int->Doc ann
。通过使用
prettyprinter
中的
prettyprinter
或类似
hcat
/
/
hsep
/
/
vcat
/
/
缩进
/…等组合器,您可以为一个类型构建一个漂亮的打印实例。因此,把所有这些放在一起:

instance Pretty Exp where
    pretty :: Exp -> Doc ann
    pretty exp = case exp of
        B bool -> pretty bool
        MyInt int -> pretty int
或者,以等式方式而不是使用
大小写

    pretty (B bool) = pretty bool
    pretty (MyInt int) = pretty int
既然B是Bool Exp,为什么不能使用它呢

B
是类型为
Bool->Exp
的构造函数,因此像
B e1
这样的表达式通过包装
e1
生成类型为
Exp
的值,该值必须是
Bool
;类似地,模式
be1
匹配
B
构造函数,并提取其字段
e1
,该字段也是
Bool
类型。所以当你写这篇文章时:

pretty (B e1) = e1
您刚才说的是“提取
Bool
字段并返回它”,但您试图在需要
Doc
时返回
Bool
。(即,此定义的类型为
Exp->Bool
,但签名需要
Exp->Doc ann

您可能会发现使用
GADTSyntax
来定义数据类型更为清晰,因为它允许您将每个构造函数的类型显式写出为
FieldType1->…->FieldTypeN->TypeName
,例如:

{-# LANGUAGE GADTSyntax #-}

data Exp where
  B :: Bool -> Exp
  MyInt :: Int -> Exp
这正是您在GHCi中询问构造函数类型时得到的签名:

> :type MyInt
MyInt :: Int -> Exp

这是非常有益的。非常感谢。我试着运行你的解决方案,得到了“不在范围内:类型构造函数或类”Pretty“,所以我假设导入对我不起作用,因为类没有导入,它对你起作用了吗?@pmichaels:如果你查看包的文档,你会发现,所以你应该从那里导入它。要获得我在这里使用的内容,可以编写
import Data.Text.Prettyprint.Doc(Doc,Pretty(…)
。您可能希望导入库的其他部分
qualified
并使用缩写,例如
import qualified Data.Text.Prettyprint.Doc作为Pretty
…作为P
,因此名称的来源总是很清楚,例如,
Pretty.nest
/
P.nest
。我已经做了一些导入更新,现在可以使用了。再次感谢您的澄清。
{-# LANGUAGE GADTSyntax #-}

data Exp where
  B :: Bool -> Exp
  MyInt :: Int -> Exp
> :type MyInt
MyInt :: Int -> Exp