Haskell 将存在主义提升到类型层次
tl;dr:我正试图重写一些依赖类型的代码,这些代码在Haskell中有一个sigma类型列表,我似乎无法为存在类型生成单例,换句话说,这段代码失败了: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 :
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版本下不起作用!