可以从Haskell中的列表中使用单例NAT(如0,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

在学习单例和(半)依赖类型时,我开始尝试从一个普通的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 -> 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
为type
0

因此
fromList
需要是一个类的方法,该类可以在
n
类型上进行分派


但是您试图将第二个参数的值分派给
fromList
——也就是说,在列表是否为空的情况下——一个依赖类型。单例库/技术是在Haskell中伪造依赖类型。这就是我的知识耗尽的地方。因此我将Peano Nats
s 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