Haskell 将存在主义提升到类型层次

Haskell 将存在主义提升到类型层次,haskell,idris,dependent-type,singleton-type,Haskell,Idris,Dependent Type,Singleton Type,tl;dr:我正试图重写一些依赖类型的代码,这些代码在Haskell中有一个sigma类型列表,我似乎无法为存在类型生成单例,换句话说,这段代码失败了: datafoo::键入where 福:福。星福->福 $(genSingletons[“Foo]) 随后是更长的版本 假设此Idris代码为模型: data AddrType = Post | Email | Office data AddrFields : AddrType -> Type where PostFields :

tl;dr:我正试图重写一些依赖类型的代码,这些代码在Haskell中有一个sigma类型列表,我似乎无法为存在类型生成单例,换句话说,这段代码失败了:

datafoo::键入where
福:福。星福->福
$(genSingletons[“Foo])

随后是更长的版本

假设此Idris代码为模型:

data AddrType = Post | Email | Office

data AddrFields : AddrType -> Type where
  PostFields : (city : String) -> (street : String) -> AddrFields Post
  EmailFields : (email : String) -> AddrFields Email
  OfficeFields : (floor : Int) -> (desk : Nat) -> AddrFields Office

Addr : Type
Addr = (t : AddrType ** AddrFields t)

someCoolPredicate : List AddrType -> Bool

data AddrList : List Addr -> Type where
  MkAddrList : (lst : List Addr) -> {auto prf : So (someCoolPredicate lst)} -> AddrList lst
基本上,当给我们一个类型为
AddrList lst
的值时,我们知道
lst:List Addr
,并且
someCoolPredicate
适用于该列表

我在现代Haskell中成功实现的最接近的目标是,假设单身-2.5:

import Data.singleton.TH
导入数据.singleton.Prelude
导入数据.singleton.Prelude.List
数据地址类型=邮政|电子邮件|办公室
推导(Eq、Ord、Show)
$(genSingletons[''AddrType])
$(SingleQInstances[''AddrType])
数据族AddrFields(a::AddrType)
数据实例AddrFields'Post=PostFields{city::String,street::String}派生(Eq,Ord,Show)
数据实例AddrFields'Email=EmailFields{Email::String}派生(Eq、Ord、Show)
数据实例AddrFields'Office=OfficeFields{flr::Int,desk::Int}派生(Eq,Ord,Show)
数据地址::键入where
地址::{addrType::Sing addrType
,addrTypeVal::AddrType
,字段::AddrFields addrType
}->地址
$(推广[d]|
someCoolPredicate::[Addr]->Bool
someCoolPredicate=。。。
|])
数据地址列表::[Addr]->输入where
AddrList::{addrs::Sing addrs,prf::SomeCoolPredicate addrs:~:'True}->AddrList addrs
但是,如果给定一个
[Addr]
,我实际上如何构造这种类型的值呢?换句话说,我如何在Idris中表达以下内容

*Addrs> MkAddrList [(Post ** PostFields "Foo" "Bar")]
MkAddrList [(Post ** PostFields "Foo" "Bar")] : AddrList [(Post ** PostFields "Foo" "Bar")]

问题是,看起来我必须能够执行
toSing
Addr
列表中的等效操作,但是
$(genSingletons[''Addr])
失败。事实上,即使是tl中的代码;dr部分失败。那么除了放弃这个想法,我应该怎么做呢?

这个问题的解决方案需要单例的单例,这是在
singletons-2.6
中介绍的。首先,所需的语言扩展和导入:

{-#语言模板Haskell、GADT、ScopedTypeVariables、PolyTypes、DataTypes、,
TypeFamilies、TypeOperator、不可判定实例、InstanceSigs、,
类型应用程序、灵活实例、独立派生#-}
模块地址在哪里
导入GHC.TypeLits
导入数据。种类
导入Data.singleton.TH
导入数据.singleton.Sigma
现在我们可以定义
AddrType
并为其生成单例:

singleton
[d |数据地址类型=邮局|电子邮件|办公室
衍生节目
|]
到目前为止没有什么特别之处,但是我们有
AddrFields
,这有点棘手:

data AddrFields::AddrType->Type where
PostFields::{city::Symbol,street::Symbol}->AddrFields Post
EmailFields::{email::Symbol}->AddrFields电子邮件
办公场地:{楼层::Nat,办公桌::Nat}->AddrFields办公室
派生实例显示(AddrFields addrType)
我不得不使用
Symbol
Nat
,而不是
String
Integer
,因为后者可以升级。然后,由于
AddrFields
本身就是一个GADT,我们必须手动将其单音化:

datasaddrfields::forall addrType。AddrFields addrType->键入其中
SPostFields::Sing city->Sing street->SAddrFields(PostFields city street)
SEmailFields::Sing email->SAddrFields(EmailFields email)
沙发场::唱台->唱台->鞍场(办公室场台)
派生实例显示(SAddrFields addrFields)
类型实例Sing=SAddrFields
实例(SingI city,SingI street)=>SingI(PostFields city street),其中
歌唱
实例(SingI-email)=>SingI(EmailFields-email)其中
sing=语义字段sing
实例(SingI楼层,SingI办公桌)=>SingI(OfficeFields楼层办公桌),其中
sing=拱腹场sing
自动化此bit是一个尚未解决的问题:

接下来,让我们定义
Addr
,它只是一个依赖对:

type Addr=Sigma AddrType(泰康AddrFields)
下面是一个
Addr
值的示例:

x::Addr
x=SPost:&:PostFields未定义未定义
PostFields
Symbol
字段不能有任何居民,因此我必须用
未定义的
来填充它们,但目前这并不重要。请注意,我们已经有了一个singleton作为第一个组件,
SPost

这就是单身人士中的单身人士发挥作用的地方。我们可以单音化
x
,如下所示:

xSing::Sing@Addr(SPost:&:PostFields“Foo”“Bar”)
xSing=sing
对于最后一位,让我们定义
someCoolPredicate
AddrList

singleton
[d]|
someCoolPredicate::[Addr]->Bool
someCoolPredicate(:)=True
someCoolPredicate[]=False
|]
数据地址列表::[Addr]->输入where
MkAddrList::(SomeCoolPredicate addrs~True)=>Sing addrs->AddrList addrs
派生实例显示(AddrList addrs)

有了这个机制,您的Idris示例
MkAddrList[(Post**PostFields“Foo”“Bar”)]
编写如下:

ghci>MkAddrList'[SPost:&:PostFields“Foo”“Bar”]sing
MkAddrList(SCons(SWrapSing{sUnwrapSing=SPost}:&:SPostFields(SSym@“Foo”)(SSym@“Bar”))SNil)

这里有完整的代码:

啊,2.6版的单件!难怪它在2.5版本下不起作用!