具有种类nat的向量的应用实例

时间:2015-10-25 16:15:53

标签: haskell data-kinds

我现在正在玩种类的nat,并在尝试定义矢量数据类型的应用实例时遇到困难。

我认为一个合理的例子是,pure 1 :: Vec 3 Int会给我一个长度为3的向量,值为1的所有元素,而<*>运算符会将值与值一起压缩。

我遇到的问题是它将是递归的,但取决于nat类的值。

如下所示,我使用了大量的pragma(我甚至不知道哪些是必要的)以及我发现的一些技巧(n ~ (1 + n0)OVERLAPPING pragma)但似乎没有一个对我有用。

问题是如果可以在Haskell中编码,如果是,我错过了什么?

{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE InstanceSigs #-}

import GHC.TypeLits


data Vec :: (Nat -> * -> *) where
  Nil  :: Vec 0 a
  Cons :: a -> Vec n a -> Vec (1 + n) a

instance Functor (Vec n) where
  fmap f Nil = Nil
  fmap f (Cons a as) = Cons (f a) (fmap f as)

instance {-# OVERLAPPING #-} Applicative (Vec 0) where
  pure _ = Nil
  a <*> b = Nil

instance {-# OVERLAPPABLE #-} n ~ (1 + n0) => Applicative (Vec n) where
  pure :: n ~ (1 + n0) => a -> Vec n a
  pure v = Cons v (pure v :: Vec n0 a)

  (<*>) :: n ~ (1 + n0) => Vec n (a -> b) -> Vec n a -> Vec n b
  (Cons f fs) <*> (Cons v vs) = Cons (f v) (fs <*> vs :: Vec n0 b)

编辑:

我得到的错误是:

Could not deduce (a ~ a1)
from the context (Functor (Vec n), n ~ (1 + n0))
  bound by the instance declaration at Vectors.hs:27:31-65
  ‘a’ is a rigid type variable bound by
      the type signature for pure :: (n ~ (1 + n0)) => a -> Vec n a
      at Vectors.hs:28:11
  ‘a1’ is a rigid type variable bound by
       an expression type signature: Vec n1 a1 at Vectors.hs:29:20
Relevant bindings include
  v :: a (bound at Vectors.hs:29:8)
  pure :: a -> Vec n a (bound at Vectors.hs:29:3)
In the first argument of ‘pure’, namely ‘v’
In the second argument of ‘Cons’, namely ‘(pure v :: Vec n0 a)’

1 个答案:

答案 0 :(得分:9)

制作此Applicative实例的方法不止一种。本杰明的评论指出了我通常这样做的方式。你尝试这样做的方式也是有道理的。原则上,至少。我担心它会在实践中挣扎,因为TypeLits机器对数字知之甚少(还)。这是问题归结为:

{-# LANGUAGE DataKinds #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE ScopedTypeVariables #-}

module AV where

import GHC.TypeLits

grumble :: forall (f :: Nat -> *) (n :: Nat)(j :: Nat)(k :: Nat).
           (n ~ (1 + j), n ~ (1 + k)) => f j -> f k
grumble x = x

给出

Could not deduce (j ~ k)
from the context (n ~ (1 + j), n ~ (1 + k))

如果Cons <*>没有确认1 +是单射的,那么说服GHC这两条尾巴的长度相同是非常棘手的。