Haskell 在运行时使用GADTs进行类型转换

Haskell 在运行时使用GADTs进行类型转换,haskell,gadt,existential-type,Haskell,Gadt,Existential Type,我正在设计一种类型化的正式语言,也就是说,一种正式语言,其中每个字母都有特定类型的表示。到目前为止,我有以下几点: {-#语言数据类型} {-#语言灵活语境#-} {-#语言灵活实例} {-#语言GADTs} {-#语言实例sigs} {-#语言等级} {-#语言范围类型变量#-} {-#语言类型#-} {-#语言类型族{-} 导入数据。种类 数据类型Y(s::c)=标记 类字符c,其中 showVal::Typey(s::ca)->a->ShowS 类别字符(字母l)=>字母l,其中 数据族字

我正在设计一种类型化的正式语言,也就是说,一种正式语言,其中每个字母都有特定类型的表示。到目前为止,我有以下几点:

{-#语言数据类型}
{-#语言灵活语境#-}
{-#语言灵活实例}
{-#语言GADTs}
{-#语言实例sigs}
{-#语言等级}
{-#语言范围类型变量#-}
{-#语言类型#-}
{-#语言类型族{-}
导入数据。种类
数据类型Y(s::c)=标记
类字符c,其中
showVal::Typey(s::ca)->a->ShowS
类别字符(字母l)=>字母l,其中
数据族字母l::*->*
数据符号l(a::字母l s),其中
终端::(字母l)=>s->符号l(a::字母l-s)
实例(字母l)=>显示(符号LA)其中
showsPrec d(终端val)=showVal(标记::类型Y a)val
--示例语言
数据示例语言=示例语言
实例字母表示例语言在哪里
数据字母示例语言a where
变量::字母ExampleLanguage字符串
Comment::Letter example语言字符串
EqualSign::Letter ExampleLanguage()
Deref::Letter ExampleLanguage()
实例字符(字母ExampleLanguage),其中
--showVal(\:Typey变量)=showString
--showVal(\:Typey Comment)=showString
--showVal(\:Typey EqualSign)=常量$showString“=”
--showVal(\:Typey Deref)=const$showString“*”
showVal=常量$showString“错误”
测试::符号示例语言注释
测试=终端“一些注释”
您可能已经看到我开始实现
showVal
,但是在这里,我在完成实现时遇到了问题。当我尝试取消注释
实例字母(Character ExampleLanguage)
中的行时,编译器很快就会抱怨:

main.hs:40:14: error:
    • Couldn't match type ‘a1’ with ‘()’
      ‘a1’ is a rigid type variable bound by
        the type signature for:
          showVal :: forall k (a :: k) a1 (s :: Character
                                                  ExampleLanguage a1).
                     Typey s -> a1 -> ShowS
        at main.hs:38:5
      Expected type: Typey 'EqualSign
        Actual type: Typey s
    • When checking that the pattern signature: Typey 'EqualSign
        fits the type of its context: Typey s
      In the pattern: _ :: Typey EqualSign
      In an equation for ‘showVal’:
          showVal (_ :: Typey EqualSign) = const $ showString "="
    • Relevant bindings include
        showVal :: Typey s -> a1 -> ShowS (bound at main.hs:38:5)
我不确定我是否理解编译器在抱怨什么。从
Character ExampleLanguage
的GADT定义可以清楚地看出,我正在尝试模式匹配不同的构造函数,根据字母输出不同的字符串


我怎样才能做到这一点?数据格式不是固定的,只要
符号
包含有关字母表、字母和字母表示类型的类型信息,就可以随意修改它。

模式匹配GADT的构造函数,而不是它们的类型

{-# LANGUAGE FlexibleContexts      #-}
{-# LANGUAGE FlexibleInstances     #-}
{-# LANGUAGE GADTs                 #-}
{-# LANGUAGE TypeFamilies          #-}

class Character c where
  showVal :: c a -> a -> ShowS

class Character (Letter l) => Alphabet l where
  data family Letter l :: * -> *

-- Example language
data ExampleLanguage = ExampleLanguage

instance Alphabet ExampleLanguage where
  data Letter ExampleLanguage a where
    Variable :: Letter ExampleLanguage String
    Comment :: Letter ExampleLanguage String
    EqualSign :: Letter ExampleLanguage ()
    Deref :: Letter ExampleLanguage ()

instance Character (Letter ExampleLanguage) where
    showVal Variable = showString
    showVal Comment = showString
    showVal EqualSign = const $ showString "="
    showVal Deref = const $ showString "*"
将此标记包含在
符号中
,以便以后可以在其上进行模式匹配

{-# LANGUAGE DataKinds             #-}
{-# LANGUAGE TypeInType            #-}

data Symbol l (a :: Letter l s) where
  Terminal :: Letter l s -> s -> Symbol l (a :: Letter l s)

instance (Alphabet l) => Show (Symbol l a) where
  showsPrec d (Terminal tag val) = showVal tag val

test :: Symbol ExampleLanguage Comment
test = Terminal Comment "some comment"

模式匹配在GADT的构造函数上,而不是在其类型上

{-# LANGUAGE FlexibleContexts      #-}
{-# LANGUAGE FlexibleInstances     #-}
{-# LANGUAGE GADTs                 #-}
{-# LANGUAGE TypeFamilies          #-}

class Character c where
  showVal :: c a -> a -> ShowS

class Character (Letter l) => Alphabet l where
  data family Letter l :: * -> *

-- Example language
data ExampleLanguage = ExampleLanguage

instance Alphabet ExampleLanguage where
  data Letter ExampleLanguage a where
    Variable :: Letter ExampleLanguage String
    Comment :: Letter ExampleLanguage String
    EqualSign :: Letter ExampleLanguage ()
    Deref :: Letter ExampleLanguage ()

instance Character (Letter ExampleLanguage) where
    showVal Variable = showString
    showVal Comment = showString
    showVal EqualSign = const $ showString "="
    showVal Deref = const $ showString "*"
将此标记包含在
符号中
,以便以后可以在其上进行模式匹配

{-# LANGUAGE DataKinds             #-}
{-# LANGUAGE TypeInType            #-}

data Symbol l (a :: Letter l s) where
  Terminal :: Letter l s -> s -> Symbol l (a :: Letter l s)

instance (Alphabet l) => Show (Symbol l a) where
  showsPrec d (Terminal tag val) = showVal tag val

test :: Symbol ExampleLanguage Comment
test = Terminal Comment "some comment"

我不知道如何用这种方法实现
实例(字母l)=>显示(符号l a)
a
是这种情况下的特定字母,但它在类型信息中,不能作为参数传递给showVal,对吗?除非GHC中有一些我不知道的进展,类型
Symbol example language Comment
没有意义,因为
Comment
是GADT的构造函数,无法升级。GHC 8让我很惊讶。我添加了如何定义
Symbol
。剩下的一个问题是:这现在是合法的:
(终端注释“某些注释”)::Symbol ExampleLanguage变量
,即如果两个字母具有相同的类型,编译器将不会发现我在构造函数中输入了不同的字母和类型,我不知道如何实现
实例(字母l)=>显示(符号l a)在这种情况下,
a
是特定的字母,但它在类型信息中,不能作为参数传递到showVal中,对吗?除非GHC中有一些我不知道的进展,否则类型
符号ExampleLanguage Comment
没有意义,因为
Comment
是G的构造函数ADT和无法升级。GHC 8让我很惊讶。我添加了如何定义
符号
。还有一个问题:这现在是合法的:
(终端注释“某些注释”)::Symbol example language Variable
即如果两个字母具有相同的类型,编译器将不会发现我在构造函数和类型中输入了不同的字母