這裏是一種方式(here is a complete Gist)。我們堅持使用Peano數字代替GHC的類型級別Nat
,因爲感應對他們更好。
{-# LANGUAGE GADTs, PolyKinds, DataKinds, TypeOperators, FlexibleInstances, FlexibleContexts #-}
import Data.Foldable
import Text.PrettyPrint.HughesPJClass
data Nat = Z | S Nat
-- Some type synonyms that simplify uses of 'Nat'
type N0 = Z
type N1 = S N0
type N2 = S N1
type N3 = S N2
type N4 = S N3
type N5 = S N4
type N6 = S N5
type N7 = S N6
type N8 = S N7
type N9 = S N8
-- Similar to lists, but indexed over their length
data Vector (dim :: Nat) a where
Nil :: Vector Z a
(:-) :: a -> Vector n a -> Vector (S n) a
infixr 5 :-
data Tensor (dim :: [Nat]) a where
Scalar :: a -> Tensor '[] a
Tensor :: Vector d (Tensor ds a) -> Tensor (d : ds) a
要顯示這些類型的,我們將使用pretty
包(其中已經自帶了GHC)。
instance (Foldable (Vector n), Pretty a) => Pretty (Vector n a) where
pPrint = braces . sep . punctuate (text ",") . map pPrint . toList
instance Pretty a => Pretty (Tensor '[] a) where
pPrint (Scalar x) = pPrint x
instance (Pretty (Tensor ds a), Pretty a, Foldable (Vector d)) => Pretty (Tensor (d : ds) a) where
pPrint (Tensor xs) = pPrint xs
當年這裏是Foldable
我們的數據類型(沒什麼好驚訝這裏 - 我包括這只是因爲你需要它的Pretty
實例編譯)實例:
instance Foldable (Vector Z) where
foldMap f Nil = mempty
instance Foldable (Vector n) => Foldable (Vector (S n)) where
foldMap f (x :- xs) = f x `mappend` foldMap f xs
instance Foldable (Tensor '[]) where
foldMap f (Scalar x) = f x
instance (Foldable (Vector d), Foldable (Tensor ds)) => Foldable (Tensor (d : ds)) where
foldMap f (Tensor xs) = foldMap (foldMap f) xs
最後,部分回答您的問題:我們可以定義Applicative (Vector n)
和Applicative (Tensor ds)
類似於如何定義Applicative ZipList
(除了pure
不返回並且空列表 - 它返回正確長度的列表)。
instance Applicative (Vector Z) where
pure _ = Nil
Nil <*> Nil = Nil
instance Applicative (Vector n) => Applicative (Vector (S n)) where
pure x = x :- pure x
(x :- xs) <*> (y :- ys) = x y :- (xs <*> ys)
instance Applicative (Tensor '[]) where
pure = Scalar
Scalar x <*> Scalar y = Scalar (x y)
instance (Applicative (Vector d), Applicative (Tensor ds)) => Applicative (Tensor (d : ds)) where
pure x = Tensor (pure (pure x))
Tensor xs <*> Tensor ys = Tensor ((<*>) <$> xs <*> ys)
然後,在ghci中,它是非常容易的,讓您的zero
功能:
ghci> :set -XDataKinds
ghci> zero = pure 0
ghci> pPrint (zero :: Tensor [N5,N3,N2] Integer)
{{{0, 0}, {0, 0}, {0, 0}},
{{0, 0}, {0, 0}, {0, 0}},
{{0, 0}, {0, 0}, {0, 0}},
{{0, 0}, {0, 0}, {0, 0}},
{{0, 0}, {0, 0}, {0, 0}}}
,你可以看看到[Data.FixedList](https://hackage.haskell.org/package/ fixed-list-0.1.6/docs/Data-FixedList.html)庫,根據具有固定長度的列表來定義類型。 – Redu
一些可能相關的鏈接:https://blog.jle.im/entry/practical-dependent-types-in-haskell-1.html https://blog.jle.im/entry/practical-dependent-types-in -haskell-2.html https://www.reddit.com/r/haskell/comments/67f4mw/naperian_tensors/也是矢量大小的軟件包http://hackage.haskell.org/package/vector-sized – danidiaz
也請請檢查Mike Izbicki在[subhask'的線性代數部分的工作](http://hackage.haskell.org/package/subhask-0.1.1.0/docs/SubHask-Algebra-Vector.html)(他做了一個很多機器學習等等,所以如果你想要走向TensorFlow的話),還有我的[linearmap-category](http://hackage.haskell.org/package/linearmap-category-0.3)。 2.0/docs/Math-LinearMap-Category.html#g:5)(它以完全基於不可知的方式定義張量,從不談論_dimensions_,而是關於_vector spaces_ - 這些也可以是無限維的)。 – leftaroundabout