我正在尝试写下Category
(有限维自由)向量空间,但我似乎无法说服GHC任何给定长度的索引向量是{ {1}}。
这就是我所拥有的:
Applicative
向量是具有长度参数
的列表{-# LANGUAGE DataKinds, PolyKinds, MultiParamTypeClasses, FunctionalDependencies, FlexibleInstances, FlexibleContexts, GADTs, DeriveTraversable, StandaloneDeriving #-}
-- | Quick(slow) and dirty typesafe vectors
module Vector where
import Control.Category
要获得该类别,我们需要矩阵乘法。明显的实施使得指数与我们通常想要的相比有点落后。
data Natural = Z | S Natural
data Vec (n :: Natural) a where
VNil :: Vec Z a
VCons :: a -> Vec n a -> Vec (S n) a
deriving instance Functor (Vec n)
deriving instance Foldable (Vec n)
deriving instance Traversable (Vec n)
修改
使用@ Probie的help,我设法解决了早期的问题,这足以为vmult :: Num a => Vec i (Vec k a) -> Vec j (Vec k a) -> Vec j (Vec i a)
-- ^ ^ ^ ^ ^ ^
vmult _ VNil = VNil
vmult xs (VCons y ys) = VCons (dotProduct y <$> xs) $ vmult xs ys
dotProduct :: Num a => Vec n a -> Vec n a -> a
dotProduct VNil VNil = 0
dotProduct (VCons x xs) (VCons y ys) = x * y + dotProduct xs ys
s
Semigroupoid
但在定义data KNat n where
KZ :: KNat Z
KS :: Finite n => KNat n -> KNat (S n)
class Finite (a :: Natural) where toFNat :: proxy a -> KNat a
instance Finite Z where toFNat _ = KZ
instance Finite n => Finite (S n) where toFNat _= KS (toFNat (Proxy :: Proxy n))
instance Finite n => Applicative (Vec n) where
pure :: forall a. a -> Vec n a
pure x = go (toFNat (Proxy :: Proxy n))
where
go :: forall (m :: Natural). KNat m -> Vec m a
go KZ = VNil
go (KS n) = VCons x $ go n
(<*>) :: forall a b. Vec n (a -> b) -> Vec n a -> Vec n b
nfs <*> nxs = go (toFNat (Proxy :: Proxy n)) nfs nxs
where
go :: forall (m :: Natural). KNat m -> Vec m (a -> b) -> Vec m a -> Vec m b
go KZ VNil VNil = VNil
go (KS n) (VCons f fs) (VCons x xs) = VCons (f x) (go n fs xs)
data Matrix a i j where
Matrix :: (Finite i, Finite j) => Vec i (Vec j a) -> Matrix a i j
instance Num a => Semigroupoid (Matrix a) where
Matrix x `o` Matrix y = Matrix (vmult (sequenceA x) y)
时遇到了类似的问题:
Category.id
我现在需要一个instance Num a => Category (Matrix a) where
(.) = o
id :: forall (n :: Natural). Matrix a n n
id = Matrix (go (toFNat (Proxy :: Proxy n)))
where
go :: forall (m :: Natural). (KNat m) -> Vec m (Vec m a)
go KZ = VNil
go (KS n) = VCons (VCons 1 (pure 0)) (VCons 0 <$> go n)
,而不需要从空中召唤Applicative (Vec n)
。
Finite n
似乎没有办法解决这方面的问题。
结束编辑
对于上下文,这就是我之前所拥有的,src/Vector.hs:59:8: error:
• Could not deduce (Finite n) arising from a use of ‘Matrix’
from the context: Num a
bound by the instance declaration at src/Vector.hs:56:10-37
Possible fix:
add (Finite n) to the context of
the type signature for:
Control.Category.id :: forall (n :: Natural). Matrix a n n
• In the expression: Matrix (go (toFNat (Proxy :: Proxy n)))
In an equation for ‘Control.Category.id’:
Control.Category.id
= Matrix (go (toFNat (Proxy :: Proxy n)))
where
go :: forall (m :: Natural). (KNat m) -> Vec m (Vec m a)
go KZ = VNil
go (KS n) = VCons (VCons 1 (pure 0)) (VCons 0 <$> go n)
In the instance declaration for ‘Category (Matrix a)’
|
59 | id = Matrix (go (toFNat (Proxy :: Proxy n)))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
是归纳的Vec n
Applicative
要获取类别实例,我们需要重新排列索引后面的instance Applicative (Vec Z) where
pure _ = VNil
_ <*> _ = VNil
instance Applicative (Vec n) => Applicative (Vec (S n)) where
pure a = VCons a $ pure a
VCons f fs <*> VCons x xs = VCons (f x) (fs <*> xs)
...
a
但是如果没有重新安排其中一个条款,就没有办法重新安排指数本身......
data Matrix a i j where
Matrix :: Vec i (Vec j a) -> Matrix a i j
然而:
instance Num a => Category (Matrix a) where
Matrix x . Matrix y = Matrix $ (vmult (sequenceA x) y)
-- ^^^^^^^^^
答案 0 :(得分:2)
我还没有在Haskell中使用依赖类型来玩太多,但这类似于应该可行的东西。我设法得到了一些可以编译的东西,但我认为这有更好的方法......
诀窍是能够生成一些可以递归的东西,其中包含足够的类型信息而不需要已经有Vector
。这允许我们将两个Applicative实例折叠到一个Applicative实例中(不幸的是添加一个约束Finite
,希望以后不会导致问题)
{-# LANGUAGE DataKinds, PolyKinds, MultiParamTypeClasses, FunctionalDependencies, FlexibleInstances, FlexibleContexts, GADTs, DeriveTraversable, StandaloneDeriving, ScopedTypeVariables #-}
module Vector where
import Control.Category
import Data.Proxy
data Natural = Z | S Natural
data SNat n where
SZ :: SNat Z
SS :: Finite n => SNat n -> SNat (S n)
class Finite (a :: Natural) where
toSNat :: proxy a -> SNat a
instance Finite Z where
toSNat _ = SZ
instance (Finite a) => Finite (S a) where
toSNat _ = SS (toSNat (Proxy :: Proxy a))
data Vec (n :: Natural) a where
VNil :: Vec Z a
VCons :: (Finite n) => a -> Vec n a -> Vec (S n) a
deriving instance Functor (Vec n)
deriving instance Foldable (Vec n)
deriving instance Traversable (Vec n)
instance (Finite n) => Applicative (Vec n) where
pure (a :: a) = go (toSNat (Proxy :: Proxy n))
where go :: forall (x :: Natural) . SNat x -> Vec x a
go SZ = VNil
go (SS m) = VCons a (go m)
(fv :: Vec n (a -> b)) <*> (xv :: Vec n a) = go (toSNat (Proxy :: Proxy n)) fv xv
where go :: forall (x :: Natural) . SNat x -> Vec x (a -> b) -> Vec x a -> Vec x b
go SZ VNil VNil = VNil
go (SS m) (VCons f fs) (VCons x xs) = VCons (f x) (go m fs xs)
vmult :: Num a => Vec i (Vec k a) -> Vec j (Vec k a) -> Vec j (Vec i a)
vmult _ VNil = VNil
vmult xs (VCons y ys) = VCons (dotProduct y <$> xs) $ vmult xs ys
dotProduct :: Num a => Vec n a -> Vec n a -> a
dotProduct VNil VNil = 0
dotProduct (VCons x xs) (VCons y ys) = x * y + dotProduct xs ys
data Matrix a i j where
Matrix :: (Finite i, Finite j) => Vec i (Vec j a) -> Matrix a i j
instance Num a => Category (Matrix a) where
Matrix x . Matrix y = Matrix $ (vmult (sequenceA x) y)
编辑:
Matrix
不是一个类别。没有身份 - 我们需要forall (n :: Natural) . Matrix a n n
不幸的是,Haskell中的所有类型都由事实证明我错了,实际上可以做到Any
居住,所以我们需要能够拥有Matrix a Any Any
,但我们只能有矩阵尺寸为&#34; true&#34; Natural
s,所以我们能做的最好的事情是forall (n :: Natural) . Finite n => Matrix a n n
答案 1 :(得分:1)
经过恐吓(以及火车上几个小时)的一些证据后,我想出了这个。
如果你将Finite
的证据推迟到最后,你可以将任何东西都加倍......我们想要写的术语是不可能的。
vdiag :: forall a i j. a -> a -> a -> KNat i -> KNat j -> Vec i (Vec j a)
vdiag u d l = go
where
go :: forall i' j'. KNat i' -> KNat j' -> Vec i' (Vec j' a)
go (KS i) (KS j) =
VCons (VCons d $ vpure u j)
(VCons l <$> go i j)
go KZ _ = VNil
go (KS i) KZ = vpure VNil (KS i)
vpure :: a -> KNat m -> Vec m a
vpure x KZ = VNil
vpure x (KS n) = VCons x $ vpure x n
但是,当我们确实需要将i
用于j
时,我们不知道Category.id
和Matrix a
是什么(除了他们是相等的)。我们CPS他们!给出data Matrix a i j where
DiagonalMatrix :: (Finite i => KNat i -> Vec i (Vec i a)) -> Matrix a i i
-- ^^^^^^^^^ ^
Matrix :: (Finite i, Finite j) => Vec i (Vec j a) -> Matrix a i j
的额外构造函数,其具有Rank 2约束。
k
任何时候我们碰巧需要增加这些东西,我们可以使用这样一个事实:我们知道另一个词的内部索引instance Num a => Semigroupoid (Matrix a) where
o :: forall a i j k. Num a => Matrix a k j -> Matrix a i k -> Matrix a i j
Matrix x `o` Matrix y =
Matrix (vmult (sequenceA x ) y)
DiagonalMatrix fx `o` Matrix y =
Matrix (vmult (sequenceA (fx (toFNat (Proxy :: Proxy k)))) y)
Matrix x `o` DiagonalMatrix fy =
Matrix (vmult (sequenceA x ) (fy (toFNat (Proxy :: Proxy k))))
是乘以的:
DiagonalMatrix fx `o` DiagonalMatrix fy = DiagonalMatrix $
\i -> vmult (sequenceA (fx i)) (fy i)
即,除非他们两个对角线。在任何情况下,它们都是相同的,所以我们现在可以使用我们后来获得的索引:
Matrix
正是因为这一步,才有必要将CPS'id
限制为只有方形的vdiag
。起初我一直尝试CPS,但这要求最终用户记住所有中间索引并证明它们,而不仅仅是结果的索引。虽然我确信这可以起作用,至少对于一个类别来说,它是不必要和严苛的。
无论如何,我们现在已经完成了,instance Num a => Category (Matrix a) where
(.) = o
id = DiagonalMatrix $ \i -> vdiag 0 1 0 i i
是CPS Matrix a
。
unMatrix :: (Finite i, Finite j) => Matrix a i j -> Vec i (Vec j a)
unMatrix (Matrix x) = x
unMatrix (DiagonalMatrix fx) = fx (toFNat (Proxy))
type Zero = Z
type One = S Z
type Two = S One
type Three = S Two
type Four = S Three
f :: Vec Two (Vec Three Int)
f = VCons (VCons 1 $ VCons 2 $ VCons 3 VNil)
$ VCons (VCons 4 $ VCons 5 $ VCons 6 VNil)
$ VNil
g :: Vec Four (Vec Two Int)
g = VCons (VCons 1 $ VCons 2 VNil)
$ VCons (VCons 3 $ VCons 4 VNil)
$ VCons (VCons 5 $ VCons 6 VNil)
$ VCons (VCons 7 $ VCons 8 VNil)
$ VNil
fg = unMatrix $ Matrix f . id . Matrix g
-- ^^
当然,从> fg
VCons (VCons 9 (VCons 12 (VCons 15 VNil))) (VCons (VCons 19 (VCons 26 (VCons 33 VNil))) (VCons (VCons 29 (VCons 40 (VCons 51 VNil))) (VCons (VCons 39 (VCons 54 (VCons 69 VNil))) VNil)))
中提取行和列要求您知道您要求的矩阵有多大。
userChoice
但这并不是太大的义务。
compare()
为了完整性,这是整个事情:https://gist.github.com/danbornside/f44907fe0afef17d5b1ce93dd36ce84d