Haskell 索引异构列表
我使用某种类型级别的编程在Haskell中构建了一个异构列表Haskell 索引异构列表,haskell,type-level-computation,Haskell,Type Level Computation,我使用某种类型级别的编程在Haskell中构建了一个异构列表 data HList a where Singleton :: HList '[] Cons :: h -> HList t -> HList (h ': t) 现在我希望能够为这个列表编制索引,但是类型存在一些问题,这使我很难做到这一点。我可以很容易地得到这个列表的开头或结尾 head :: HList (h ': t) -> h head (Cons a _) = a tail :: HList (h
data HList a where
Singleton :: HList '[]
Cons :: h -> HList t -> HList (h ': t)
现在我希望能够为这个列表编制索引,但是类型存在一些问题,这使我很难做到这一点。我可以很容易地得到这个列表的开头或结尾
head :: HList (h ': t) -> h
head (Cons a _) = a
tail :: HList (h ': t) -> HList t
tail (Cons _ b) = b
然而,索引列表是非常不同的,因为输出的类型取决于我们传递的索引。因此,我们的类型看起来很天真:
fromIndex :: (Num a) => a -> (HList b) -> ???
然而,确定?
是相当困难的。因此,我们不需要取一个Num
值,而需要取其他值。我的想法(下面的代码)是创建一个新的Natural
和一个IndexType
类,该类具有函数依赖性,允许我们仅从输入的类型中找到结果的类型
{-# Language GADTs, DataKinds, TypeOperators, FunctionalDependencies, FlexibleInstances, FlexibleContexts, UndecidableInstances #-}
data Nat = Z | S Nat
data Natural a where
Zero :: Natural 'Z
Succ :: Natural a -> Natural ('S a)
data HList a where
Singleton :: HList '[]
Cons :: h -> HList t -> HList (h ': t)
class IndexType a b c | a b -> c
instance IndexType (Natural 'Z) (HList (h ': t)) h
instance IndexType (Natural n) (HList t) a => IndexType (Natural ('S n)) (HList (h ': t)) a
fromIndex :: (IndexType (Natural n) (HList l) a) => (Natural n) -> (HList l) -> a
fromIndex (Zero) (Cons x Singleton) = x
fromIndex (Succ a) (Cons _ (xs)) = fromIndex a xs
我们的IndexType
类确实有效。如果我只测试类型类
class Test a | -> a
where test :: a
instance (IndexType (Natural ('S ('S ('S 'Z)))) (HList (Int ': String ': Char ': (Int -> String) ': Int ': '[])) a) => Test a
我们得到了正确的结果:
*Main> :t test
test :: Int -> String
然而,ghc无法验证我们的类型签名,我们得到了一个相当大的错误:
test.hs:28:39: error:
• Could not deduce: h ~ a
from the context: n ~ 'Z
bound by a pattern with constructor: Zero :: Natural 'Z,
in an equation for ‘fromIndex’
at test.hs:28:12-15
or from: l ~ (h : t)
bound by a pattern with constructor:
Cons :: forall h (t :: [*]). h -> HList t -> HList (h : t),
in an equation for ‘fromIndex’
at test.hs:28:19-34
or from: t ~ '[]
bound by a pattern with constructor: Singleton :: HList '[],
in an equation for ‘fromIndex’
at test.hs:28:26-34
‘h’ is a rigid type variable bound by
a pattern with constructor:
Cons :: forall h (t :: [*]). h -> HList t -> HList (h : t),
in an equation for ‘fromIndex’
at test.hs:28:19-34
‘a’ is a rigid type variable bound by
the type signature for:
fromIndex :: forall (n :: Nat) (l :: [*]) a.
IndexType (Natural n) (HList l) a =>
Natural n -> HList l -> a
at test.hs:27:1-81
• In the expression: x
In an equation for ‘fromIndex’:
fromIndex (Zero) (Cons x Singleton) = x
• Relevant bindings include
x :: h (bound at test.hs:28:24)
fromIndex :: Natural n -> HList l -> a (bound at test.hs:28:1)
|
28 | fromIndex (Zero) (Cons x Singleton) = x
| ^
test.hs:29:36: error:
• Could not deduce (IndexType (Natural a1) (HList t) a)
arising from a use of ‘fromIndex’
from the context: IndexType (Natural n) (HList l) a
bound by the type signature for:
fromIndex :: forall (n :: Nat) (l :: [*]) a.
IndexType (Natural n) (HList l) a =>
Natural n -> HList l -> a
at test.hs:27:1-81
or from: n ~ 'S a1
bound by a pattern with constructor:
Succ :: forall (a :: Nat). Natural a -> Natural ('S a),
in an equation for ‘fromIndex’
at test.hs:29:12-17
or from: l ~ (h : t)
bound by a pattern with constructor:
Cons :: forall h (t :: [*]). h -> HList t -> HList (h : t),
in an equation for ‘fromIndex’
at test.hs:29:21-31
• In the expression: fromIndex a xs
In an equation for ‘fromIndex’:
fromIndex (Succ a) (Cons _ (xs)) = fromIndex a xs
|
29 | fromIndex (Succ a) (Cons _ (xs)) = fromIndex a xs
| ^^^^^^^^^^^^^^
Failed, no modules loaded.
可以建立索引函数吗?有没有办法让GHC推断出我的类型签名是正确的?您的
fromIndex
案例有不同的类型!它们需要在实例中
class IndexType (n :: Nat) (xs :: [Type]) (i :: Type) | n xs -> i where
fromIndex :: Natural n -> HList xs -> i
instance IndexType Z (x ': xs) x where
fromIndex Zero (Cons x _) = x
instance IndexType n xs a => IndexType (S n) (x ': xs) a where
fromIndex (Succ n) (Cons _ xs) = fromIndex n xs
(我对
fromIndex::Natural n->HList xs->I
的类型做了一些修改。这实际上并没有改变任何事情-您的解决方案也可以工作,尽管如果您在意外的上下文中调用fromIndex
,会出现更混乱的错误消息。)我将定义以下内容:
-- The type of numbers n such that xs !! n = x
-- Compare to Nat
data Elem (x :: k) (xs :: [k]) where
Here :: Elem x (x : xs)
There :: Elem x xs -> Elem x (y : xs)
然后您发现HList
s同构于“索引函数”(同样Vect n a
同构于Fin n->a
),涉及以下类型:
indexHList :: forall xs. HList xs -> (forall x. Elem x xs -> x)
indexHList (Cons x _) Here = x
indexHList (Cons _ xs) (There i) = indexHList xs i
indexHList Singleton impossible = case impossible of {}
-- unindexHList ::ish forall xs. (forall x. Elem x xs -> x) -> HList xs
-- is a bit more work (and doesn't really have that type)
-- but is conceptually the other half of the isomorphism.
用法:
xs :: HList [Int, String, HList '[]]
xs = Cons 5 $ Cons "hello" $ Cons Singleton $ Singleton
-- Here :: Elem Int (Int:_)
indexHList xs Here == 5
-- Here :: Elem String (String:_)
-- There Here :: Elem String (_:String:_)
indexHList xs (There Here) == "hello"
与基于类的技术相比,Elem x xs
基本上是存在的。(自然n,索引类型(自然n)(HList xs)x)
。作为一种可以检查的数据类型,它比类更容易操作