vector-space-0.3.1: src/Data/Basis.hs
-- WARNING: this module depends on type families working fairly well, and
-- requires ghc version at least 6.9. I didn't find a way to specify that
-- dependency in the .cabal.
--
{-# LANGUAGE TypeOperators, TypeFamilies, UndecidableInstances
, FlexibleInstances, MultiParamTypeClasses
#-}
{-# OPTIONS_GHC -Wall -fno-warn-orphans #-}
----------------------------------------------------------------------
-- |
-- Module : Data.Basis
-- Copyright : (c) Conal Elliott 2008
-- License : BSD3
--
-- Maintainer : conal@conal.net
-- Stability : experimental
--
-- Basis of a vector space, as an associated type
----------------------------------------------------------------------
module Data.Basis
(
HasBasis(..)
) where
import Control.Arrow (second)
import Data.Either
import Data.VectorSpace
class VectorSpace v s => HasBasis v s where
type Basis v :: *
basisValue :: Basis v -> v
decompose :: v -> [(s, Basis v)]
-- TODO: switch from fundep to associated type. eliminate the second type
-- parameter in VectorSpace and HasBasis.
-- Blocking bug: http://hackage.haskell.org/trac/ghc/ticket/2448
instance HasBasis Float Float where
type Basis Float = ()
basisValue () = 1
decompose s = [(s,())]
instance HasBasis Double Double where
type Basis Double = ()
basisValue () = 1
decompose s = [(s,())]
instance (HasBasis u s, HasBasis v s) => HasBasis (u,v) s where
type Basis (u,v) = Basis u `Either` Basis v
basisValue (Left a) = (basisValue a, zeroV)
basisValue (Right b) = (zeroV, basisValue b)
decompose (u,v) = decomp2 Left u ++ decomp2 Right v
decomp2 :: HasBasis w s => (Basis w -> b) -> w -> [(s, b)]
decomp2 inject = fmap (second inject) . decompose
instance (HasBasis u s, HasBasis v s, HasBasis w s) => HasBasis (u,v,w) s where
type Basis (u,v,w) = Basis (u,(v,w))
basisValue = unnest3 . basisValue
decompose = decompose . nest3
unnest3 :: (a,(b,c)) -> (a,b,c)
unnest3 (a,(b,c)) = (a,b,c)
nest3 :: (a,b,c) -> (a,(b,c))
nest3 (a,b,c) = (a,(b,c))
-- Without UndecidableInstances:
--
-- Application is no smaller than the instance head
-- in the type family application: Basis (u, (v, w))
-- (Use -fallow-undecidable-instances to permit this)
-- In the type synonym instance declaration for `Basis'
-- In the instance declaration for `HasBasis (u, v, w)'
--
-- A work-around:
--
-- type Basis (u,v,w) = Basis u `Either` Basis (v,w)
{-
---- Testing
t1 = basisValue () :: Float
t2 = basisValue () :: Double
t3 = basisValue (Right ()) :: (Float,Double)
t4 = basisValue (Right (Left ())) :: (Float,Double,Float)
-}