3

所以我正在使用Data.VectorSpace并且我正在尝试扩展force-layout

现在我想产生一个多态的'1'-标量。也就是说,如果将标量与向量相乘,则无论该向量的类型(参数)如何,都会产生相同的向量。可能吗?有没有有用的解决方法?

这是一个更具体的代码示例(它从我在这里使用的代码继续):

data Particle v = Particle { _pos   :: Point v
                           , _vel   :: v
                           , _force :: v
                           , _mass  :: Scalar v
                           }
-- .. standalone Show and Eq omitted 
initParticle :: AdditiveGroup v => Point v -> Particle v
initParticle p = Particle p zeroV zeroV unitScalar

unitScalar = undefined

-- Should always be true:
testInit :: Point (Double,Double) -> Bool
testInit p = ((_mass (initParticle p)) == 1::Double)

如何在上面定义“unitScalar”?

4

1 回答 1

6

您定义的上下文是不可能的;既然你说那v是一个AdditiveGroup,那就是它的全部,因此没有其他属性可以归因于v

您当然可以定义其他定义单位值的类:

{-# LANGUAGE FlexibleContexts #-}
module Main (main) where

import Data.VectorSpace

如果我们想在数学上严格,我们可能会做以下事情;但是,这在 Haskell 中会产生不良后果,因为只能为一种类型定义一个 Monoid,因此下面的解决方案可能更好。

-- BAD SOLUTION! (Arguably)
import Data.Monoid

instance Monoid Double where
  mempty = 1
  mappend = (*)

相反,我们定义了一个general MultiplicativeGroup,它也是乘法的幺半群。

class MultiplicativeGroup a where
  unit :: a
  multiply :: a -> a -> a
  reciprocal :: a -> a

instance MultiplicativeGroup Double where
  unit = 1
  multiply = (*)
  reciprocal = (1 /)

现在我们可以实现工作示例:

data Particle v =
  Particle -- Removed Point for this example since I don't have its definition
  { _vel :: v
  , _force :: v
  , _mass :: Scalar v
  }

-- We need VectorSpace because there needs to be a Scalar type associated with v
-- Also, this context requires you to use FlexibleContexts, which should be
-- harmless
initParticle :: (VectorSpace v, MultiplicativeGroup (Scalar v))
             => Particle v
initParticle = Particle zeroV zeroV unit

-- Works as expected:
main :: IO ()
main = print $ ((_mass (initParticle :: Particle Double)) == (1::Double))

顺便说一句,您当然可以替换MultiplicativeGroupwithNum和替换unitwith 1,但这会给您带来比您想要的更多的功能。

PS。你应该看看优秀的algebra,它为你做这种事情更严格。在它之上实施力求解器不会太难。

于 2012-06-14T19:36:37.860 回答