Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/.htaccess/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell 类型级别列表上的相等约束_Haskell_Dependent Type_Type Level Computation - Fatal编程技术网

Haskell 类型级别列表上的相等约束

Haskell 类型级别列表上的相等约束,haskell,dependent-type,type-level-computation,Haskell,Dependent Type,Type Level Computation,我试图强制执行一个类型级别的约束,即类型级别列表的长度必须与所携带的类型级别Nat的长度相同。例如,使用Singleton[1]包的长度: 数据n~Length ls=>NumList n::Nat ls::[*] 测试::代理NumList 2'[Bool,String,Int] 测试=代理 我不希望编译此代码,因为存在不匹配 编辑:正如dfeuer提到的,数据类型上下文不是一个好主意。我可以在值级别进行比较,但我希望能够在类型级别进行比较: NumListLen a类 sameLen::代理

我试图强制执行一个类型级别的约束,即类型级别列表的长度必须与所携带的类型级别Nat的长度相同。例如,使用Singleton[1]包的长度:

数据n~Length ls=>NumList n::Nat ls::[*] 测试::代理NumList 2'[Bool,String,Int] 测试=代理 我不希望编译此代码,因为存在不匹配

编辑:正如dfeuer提到的,数据类型上下文不是一个好主意。我可以在值级别进行比较,但我希望能够在类型级别进行比较:

NumListLen a类 sameLen::代理a->Bool 实例KnownNat n,KnownNat Length m=>numlisten NumList n m其中 sameLen=const$natVal Proxy::Proxy n==natVal Proxy::Proxy Length m ~~~~

编辑:Sorta回答了我自己的问题,只需将约束添加到实例:

NumListLen a类 sameLen::代理a->Bool 实例KnownNat n,KnownNat Length m,n~Length m=>numlisten NumList n m其中 sameLen=const$natVal Proxy::Proxy n==natVal Proxy::Proxy Length m
[1]

一个选项可能是使用类型族:

data Nat = Z | S Nat

type family LengthIs (n :: Nat) (xs :: [*]) :: Bool where
  LengthIs 'Z '[] = 'True
  LengthIs ('S n) (x ': xs) = LengthIs n xs
  LengthIs n xs = 'False

test :: LengthIs ('S ('S 'Z)) '[Bool,String,Int] ~ 'True => ()
test = ()

这将无法通过类型检查器;使其通过的唯一方法是使类型列表具有两个元素。我不知道Nat在Singleton库中是如何工作的,但我想您可能可以做类似的事情。

一个选项可能是使用类型族:

data Nat = Z | S Nat

type family LengthIs (n :: Nat) (xs :: [*]) :: Bool where
  LengthIs 'Z '[] = 'True
  LengthIs ('S n) (x ': xs) = LengthIs n xs
  LengthIs n xs = 'False

test :: LengthIs ('S ('S 'Z)) '[Bool,String,Int] ~ 'True => ()
test = ()

这将无法通过类型检查器;使其通过的唯一方法是使类型列表具有两个元素。我不知道Nat在Singleton库中是如何工作的,但我想您可能可以做类似的事情。

如果这是一个不变量,那么您应该将证明存储在数据类型中:

{-# LANGUAGE PolyKinds, UndecidableInstances #-} 

import GHC.TypeLits 

type family Length (xs :: [k]) :: Nat where 
  Length '[] = 0 
  Length (x ': xs) = 1 + Length xs 

data TList n l where 
  TList :: (Length xs ~ n) => TList n xs 
注意,虽然证明在类型级别仍然可用,但它在某种程度上隐藏在数据构造函数后面。您只需通过模式匹配即可恢复证据:

data (:~:) a b where Refl :: a :~: a 

test :: TList n l -> Length l :~: n 
test TList = Refl 
现在,两个参数之间的不匹配是一种类型错误:

bad :: TList 3 '[Int, Bool]
bad = TList 

good :: TList 2 '[Int, Bool]
good = TList 
当然,这仍然可以被底部值打败,所以

uh_oh :: TList 10 '[] 
uh_oh = undefined 

为了避免这种情况,只需确保始终在TList构造函数上进行模式匹配

如果这看起来像是一个不变量,那么应该将证明存储在数据类型中:

{-# LANGUAGE PolyKinds, UndecidableInstances #-} 

import GHC.TypeLits 

type family Length (xs :: [k]) :: Nat where 
  Length '[] = 0 
  Length (x ': xs) = 1 + Length xs 

data TList n l where 
  TList :: (Length xs ~ n) => TList n xs 
注意,虽然证明在类型级别仍然可用,但它在某种程度上隐藏在数据构造函数后面。您只需通过模式匹配即可恢复证据:

data (:~:) a b where Refl :: a :~: a 

test :: TList n l -> Length l :~: n 
test TList = Refl 
现在,两个参数之间的不匹配是一种类型错误:

bad :: TList 3 '[Int, Bool]
bad = TList 

good :: TList 2 '[Int, Bool]
good = TList 
当然,这仍然可以被底部值打败,所以

uh_oh :: TList 10 '[] 
uh_oh = undefined 


为了避免这种情况,只需确保始终在TList构造函数上进行模式匹配

这是一个数据类型上下文。数据类型上下文是完全无用的。我怀疑你还不能完全做到你在Haskell中想要做的事情,但是单身可以做一些奇怪的事情……是的,你是对的,数据类型上下文并不是我想要做的。但他们明白了这一点。我能够具体化类型值并在值级别进行比较,但这不是我想要做的。您能更好地解释一下您的最终目标是什么吗?你想表达什么,真的吗?我只想得到一个类型级别的nat和一个类型级别的列表,并在类型级别检查n~Length ls,我不想在值级别这样做。我用额外的细节编辑了我的作品。你看过像Data.Singleton.Prelude.Eq这样可怕的东西吗?我不知道该怎么理解,但可能有一种更简单的方法,那就是数据类型上下文。数据类型上下文是完全无用的。我怀疑你还不能完全做到你在Haskell中想要做的事情,但是单身可以做一些奇怪的事情……是的,你是对的,数据类型上下文并不是我想要做的。但他们明白了这一点。我能够具体化类型值并在值级别进行比较,但这不是我想要做的。您能更好地解释一下您的最终目标是什么吗?你想表达什么,真的吗?我只想得到一个类型级别的nat和一个类型级别的列表,并在类型级别检查n~Length ls,我不想在值级别这样做。我用额外的细节编辑了我的作品。你看过像Data.Singleton.Prelude.Eq这样可怕的东西吗?我不知道该怎么解释,但可能有一个更简单的方法。很好的例子,但我想使用GHC的内置类型NAT。而且我回答了我自己的问题!很好的例子,但我想使用GHC的内置类型NAT。而且我回答了我自己的问题!太好了,这和我要找的很接近!尽管如此,我如何使用代理来实现这一点呢?是的,我想随身携带这个不变量。但我不想定义一个单独的TList,它应该使用Proxy。不可能-Proxy的整个要点是它不携带类型信息。我不明白你为什么需要特别使用代理——你总是可以生成一个代理
无论如何。当然,您可以简单地将约束放置在需要的位置并在那里使用代理:Length xs~n=>Proxy xs->Proxy n->。。。但是你没有正确的by-construction属性。嗯,真的,对我来说,代理似乎和你说的完全相反,它不携带数据,它只是用来保存类型。虽然我可能完全错了。Proxy::Proxy x在运行时与任何类型的x同构。它不以任何容量存储x类型。对于TList来说,情况并非如此。在运行时,约束变成了具体的值,因此TList的类型本质上是TList::胁迫长度xs n->TList n xs-胁迫是GHC用来表示类型相等的内部类型-它是两种类型相等的运行时见证,因此是运行时类型信息。很好,这与我所寻找的非常接近!尽管如此,我如何使用代理来实现这一点呢?是的,我想随身携带这个不变量。但我不想定义一个单独的TList,它应该使用Proxy。不可能-Proxy的整个要点是它不携带类型信息。我不明白你为什么需要特别使用代理——你总是可以生成一个代理。当然,您可以简单地将约束放置在需要的位置并在那里使用代理:Length xs~n=>Proxy xs->Proxy n->。。。但是你没有正确的by-construction属性。嗯,真的,对我来说,代理似乎和你说的完全相反,它不携带数据,它只是用来保存类型。虽然我可能完全错了。Proxy::Proxy x在运行时与任何类型的x同构。它不以任何容量存储x类型。对于TList来说,情况并非如此。在运行时,约束变成了具体的值,因此TList的类型本质上是TList::concurvation Length xs n->TList n xs-concurvation是GHC用来表示类型相等的内部类型-它是两种类型相等的运行时见证,因此是运行时类型信息。