可以从Haskell中的列表中使用单例NAT(如0,1,…)生成一个大小合适的列表吗?
在学习单例和(半)依赖类型时,我开始尝试从一个普通的Haskell列表中创建一个大小为0、1、2、3等NAT给定大小的列表,。。。而不是Z、sz、S(sz)等。。顺便说一句,我正在使用Data.Singletons.TypeLits库(Singletons-2.5.1) 这就是我一直尝试的方法:可以从Haskell中的列表中使用单例NAT(如0,1,…)生成一个大小合适的列表吗?,haskell,dependent-type,type-level-computation,singleton-type,Haskell,Dependent Type,Type Level Computation,Singleton Type,在学习单例和(半)依赖类型时,我开始尝试从一个普通的Haskell列表中创建一个大小为0、1、2、3等NAT给定大小的列表,。。。而不是Z、sz、S(sz)等。。顺便说一句,我正在使用Data.Singletons.TypeLits库(Singletons-2.5.1) 这就是我一直尝试的方法: data NatList (a :: *) (n :: Nat) where Nah :: NatList a 0 Yea :: a -> NatList a n -> Na
data NatList (a :: *) (n :: Nat) where
Nah :: NatList a 0
Yea :: a -> NatList a n -> NatList a (n + 1)
fromList :: SNat n -> [a] -> NatList a n
fromList s [] = Nah
fromList s (x:xs) = Yea x (fromList (s %- (SNat :: SNat 1)) xs)
这段代码没有编译,给了我一个错误
“无法将类型'n'与'0'匹配”
“n”是一个刚性类型变量,由
以下项的类型签名:
fromList::forall(n::Nat)a.SNat n->[a]->NatList a n我不知道该库,但据我所知,问题似乎出现在
fromList
的第一个子句中,它应该只在n=0时匹配
--。。。
fromlist0[]=Nah
--...
您对fromList
的签名表示它适用于任何类型n::Nat
。但第一个等式返回Nah
,这要求n
为type0
因此fromList
需要是一个类的方法,该类可以在n
类型上进行分派
但是您试图将第二个参数的值分派给
fromList
——也就是说,在列表是否为空的情况下——一个依赖类型。单例库/技术是在Haskell中伪造依赖类型。这就是我的知识耗尽的地方。因此我将Peano Natss Z
用于实例,而不是GADT 离开这个问题一段时间后,我回来找到了一个适合我的解决方案:对大小列表类型使用存在包装器,并转换运行时列表
对那件事
这里,SomeSL将我的问题中的SizedList类型与单例nat一起包装,允许函数通过snatn访问长度
Justin Le关于Singleton的一系列博文非常有用:这个等式使用了
0
作为一个值。Singleton要求它是一个类型。我认为如果结果类型中没有Maybe
或类似的东西,这是不可能的。这个函数声称从未知大小的列表。没有关于[a]
列表大小的类型级别信息。如果像这样调用fromList(sing::sing 3)[1]
?您的函数原则上是可靠的(正如@davidyong所指出的,它是一个部分函数,但很容易修复)。问题是您不能以这种方式对类型级别的Nat执行归纳-您必须使用归纳自然(即,data Nat=Z | S Nat的升级版本
)。因此,我假设需要以某种方式对单例存在(SNat::SNat 0)进行模式匹配,对吗?是否有任何方法使用类型族来实现这种模式匹配?“模式匹配?”“表示在术语/值级别。不,这不起作用。你需要“实例匹配”。是的,类型族(实例)可以这样做。我认为你需要研究一些单例的官方示例。是的,我有点认为类型族可以这样做,尽管我仍然不确定如何在这个示例中使用类型族。
data SizedList (a :: *) (n :: Nat) where
Nil :: SizedList a 0
Cons :: a -> SizedList a n -> SizedList a (n+1)
data SomeSL (a :: *) where
MkSomeSL :: KnownNat n => SNat n -> SizedList a n -> SomeSL a
toList :: SizedList a n -> [a]
toList Nil = []
toList (Cons x xs) = x : toList xs
fromList :: [a] -> SomeSL a
fromList [] = MkSomeSL (SNat @0) Nil
fromList (x:xs) = case (fromList xs) of
MkSomeSL n ys -> MkSomeSL (n %+ SNat @1) (Cons x ys)
toList_ :: SomeSL a -> [a]
toList_ (MkSomeSL _ xs) = toList xs