packages feed

force-layout 0.3.0.11 → 0.4.0.0

raw patch · 4 files changed

+172/−145 lines, 4 filesdep +lineardep −vector-spacedep −vector-space-pointsdep ~basedep ~lensPVP ok

version bump matches the API change (PVP)

Dependencies added: linear

Dependencies removed: vector-space, vector-space-points

Dependency ranges changed: base, lens

API changes (from Hackage documentation)

- Physics.ForceLayout: instance Eq v => Eq (Particle v)
- Physics.ForceLayout: instance Fractional (Scalar v) => Default (ForceLayoutOpts v)
- Physics.ForceLayout: instance Show v => Show (Particle v)
+ Physics.ForceLayout: instance Eq (v n) => Eq (Particle v n)
+ Physics.ForceLayout: instance Fractional n => Default (ForceLayoutOpts n)
- Physics.ForceLayout: Ensemble :: [([Edge], Point v -> Point v -> v)] -> Map PID (Particle v) -> Ensemble v
+ Physics.ForceLayout: Ensemble :: [([Edge], Point v n -> Point v n -> v n)] -> Map PID (Particle v n) -> Ensemble v n
- Physics.ForceLayout: FLOpts :: Scalar v -> Maybe (Scalar v) -> Maybe Int -> ForceLayoutOpts v
+ Physics.ForceLayout: FLOpts :: n -> Maybe n -> Maybe Int -> ForceLayoutOpts n
- Physics.ForceLayout: Particle :: Point v -> v -> v -> Particle v
+ Physics.ForceLayout: Particle :: Point v n -> v n -> v n -> Particle v n
- Physics.ForceLayout: _damping :: ForceLayoutOpts v -> Scalar v
+ Physics.ForceLayout: _damping :: ForceLayoutOpts n -> n
- Physics.ForceLayout: _energyLimit :: ForceLayoutOpts v -> Maybe (Scalar v)
+ Physics.ForceLayout: _energyLimit :: ForceLayoutOpts n -> Maybe n
- Physics.ForceLayout: _force :: Particle v -> v
+ Physics.ForceLayout: _force :: Particle v n -> v n
- Physics.ForceLayout: _forces :: Ensemble v -> [([Edge], Point v -> Point v -> v)]
+ Physics.ForceLayout: _forces :: Ensemble v n -> [([Edge], Point v n -> Point v n -> v n)]
- Physics.ForceLayout: _particles :: Ensemble v -> Map PID (Particle v)
+ Physics.ForceLayout: _particles :: Ensemble v n -> Map PID (Particle v n)
- Physics.ForceLayout: _pos :: Particle v -> Point v
+ Physics.ForceLayout: _pos :: Particle v n -> Point v n
- Physics.ForceLayout: _stepLimit :: ForceLayoutOpts v -> Maybe Int
+ Physics.ForceLayout: _stepLimit :: ForceLayoutOpts n -> Maybe Int
- Physics.ForceLayout: _vel :: Particle v -> v
+ Physics.ForceLayout: _vel :: Particle v n -> v n
- Physics.ForceLayout: coulombForce :: (InnerSpace v, Floating (Scalar v)) => Scalar v -> Point v -> Point v -> v
+ Physics.ForceLayout: coulombForce :: (Metric v, Floating n) => n -> Point v n -> Point v n -> v n
- Physics.ForceLayout: damping :: Lens' (ForceLayoutOpts v_abN9) (Scalar v_abN9)
+ Physics.ForceLayout: damping :: Lens' (ForceLayoutOpts n_aaX7) n_aaX7
- Physics.ForceLayout: data Ensemble v
+ Physics.ForceLayout: data Ensemble v n
- Physics.ForceLayout: data ForceLayoutOpts v
+ Physics.ForceLayout: data ForceLayoutOpts n
- Physics.ForceLayout: data Particle v
+ Physics.ForceLayout: data Particle v n
- Physics.ForceLayout: distForce :: (InnerSpace v, Floating (Scalar v)) => (Scalar v -> Scalar v) -> Point v -> Point v -> v
+ Physics.ForceLayout: distForce :: (Metric v, Floating n) => (n -> n) -> Point v n -> Point v n -> v n
- Physics.ForceLayout: energyLimit :: Lens' (ForceLayoutOpts v_abN9) (Maybe (Scalar v_abN9))
+ Physics.ForceLayout: energyLimit :: Lens' (ForceLayoutOpts n_aaX7) (Maybe n_aaX7)
- Physics.ForceLayout: ensembleStep :: VectorSpace v => Scalar v -> Ensemble v -> Ensemble v
+ Physics.ForceLayout: ensembleStep :: (Additive v, Num n) => n -> Ensemble v n -> Ensemble v n
- Physics.ForceLayout: force :: Lens' (Particle v_a9fM) v_a9fM
+ Physics.ForceLayout: force :: Lens' (Particle v_a8JL n_a8JM) (v_a8JL n_a8JM)
- Physics.ForceLayout: forceLayout :: (InnerSpace v, Ord (Scalar v), Num (Scalar v)) => ForceLayoutOpts v -> Ensemble v -> Ensemble v
+ Physics.ForceLayout: forceLayout :: (Metric v, Num n, Ord n) => ForceLayoutOpts n -> Ensemble v n -> Ensemble v n
- Physics.ForceLayout: forces :: Lens' (Ensemble v_abBj) [([Edge], Point v_abBj -> Point v_abBj -> v_abBj)]
+ Physics.ForceLayout: forces :: Lens' (Ensemble v_aaRL n_aaRM) [([Edge], Point v_aaRL n_aaRM -> Point v_aaRL n_aaRM -> v_aaRL n_aaRM)]
- Physics.ForceLayout: hookeForce :: (InnerSpace v, Floating (Scalar v)) => Scalar v -> Scalar v -> Point v -> Point v -> v
+ Physics.ForceLayout: hookeForce :: (Metric v, Floating n) => n -> n -> Point v n -> Point v n -> v n
- Physics.ForceLayout: initParticle :: AdditiveGroup v => Point v -> Particle v
+ Physics.ForceLayout: initParticle :: (Additive v, Num n) => Point v n -> Particle v n
- Physics.ForceLayout: kineticEnergy :: (InnerSpace v, Num (Scalar v)) => Ensemble v -> Scalar v
+ Physics.ForceLayout: kineticEnergy :: (Metric v, Num n) => Ensemble v n -> n
- Physics.ForceLayout: particleStep :: VectorSpace v => Scalar v -> Particle v -> Particle v
+ Physics.ForceLayout: particleStep :: (Additive v, Num n) => n -> Particle v n -> Particle v n
- Physics.ForceLayout: particles :: Lens' (Ensemble v_abBj) (Map PID (Particle v_abBj))
+ Physics.ForceLayout: particles :: Lens' (Ensemble v_aaRL n_aaRM) (Map PID (Particle v_aaRL n_aaRM))
- Physics.ForceLayout: pos :: Lens' (Particle v_a9fM) (Point v_a9fM)
+ Physics.ForceLayout: pos :: Lens' (Particle v_a8JL n_a8JM) (Point v_a8JL n_a8JM)
- Physics.ForceLayout: recalcForces :: AdditiveGroup v => Ensemble v -> Ensemble v
+ Physics.ForceLayout: recalcForces :: (Additive v, Num n) => Ensemble v n -> Ensemble v n
- Physics.ForceLayout: simulate :: (InnerSpace v, Ord (Scalar v), Num (Scalar v)) => ForceLayoutOpts v -> Ensemble v -> [Ensemble v]
+ Physics.ForceLayout: simulate :: (Metric v, Num n, Ord n) => ForceLayoutOpts n -> Ensemble v n -> [Ensemble v n]
- Physics.ForceLayout: stepLimit :: Lens' (ForceLayoutOpts v_abN9) (Maybe Int)
+ Physics.ForceLayout: stepLimit :: Lens' (ForceLayoutOpts n_aaX7) (Maybe Int)
- Physics.ForceLayout: vel :: Lens' (Particle v_a9fM) v_a9fM
+ Physics.ForceLayout: vel :: Lens' (Particle v_a8JL n_a8JM) (v_a8JL n_a8JM)

Files

+ CHANGELOG.md view
@@ -0,0 +1,101 @@+# Change Log++## [v0.4.0.0](https://github.com/diagrams/force-layout/tree/v0.4.0.0) (2015-04-19)++* Release to accompany `diagrams-1.3`++## [v0.3.0.11](https://github.com/diagrams/force-layout/tree/v0.3.0.11) (2015-04-03)++[Full Changelog](https://github.com/diagrams/force-layout/compare/v0.3.0.10...v0.3.0.11)++## [v0.3.0.10](https://github.com/diagrams/force-layout/tree/v0.3.0.10) (2015-03-12)++[Full Changelog](https://github.com/diagrams/force-layout/compare/v0.3.0.9...v0.3.0.10)++**Closed issues:**++- cabal file category should be Physics [\#6](https://github.com/diagrams/force-layout/issues/6)++**Merged pull requests:**++- Bump base upper bound [\#5](https://github.com/diagrams/force-layout/pull/5) ([bgamari](https://github.com/bgamari))++## [v0.3.0.9](https://github.com/diagrams/force-layout/tree/v0.3.0.9) (2015-01-13)++[Full Changelog](https://github.com/diagrams/force-layout/compare/v0.3.0.8...v0.3.0.9)++## [v0.3.0.8](https://github.com/diagrams/force-layout/tree/v0.3.0.8) (2014-11-17)++[Full Changelog](https://github.com/diagrams/force-layout/compare/v0.3.0.7...v0.3.0.8)++**Merged pull requests:**++- Linear [\#3](https://github.com/diagrams/force-layout/pull/3) ([cchalmers](https://github.com/cchalmers))++- Bump lens upper version bounds [\#4](https://github.com/diagrams/force-layout/pull/4) ([RyanGlScott](https://github.com/RyanGlScott))++## [v0.3.0.7](https://github.com/diagrams/force-layout/tree/v0.3.0.7) (2014-08-22)++[Full Changelog](https://github.com/diagrams/force-layout/compare/v0.3.0.6...v0.3.0.7)++**Closed issues:**++- Needs Hackage release for lens-4.3 [\#2](https://github.com/diagrams/force-layout/issues/2)++## [v0.3.0.6](https://github.com/diagrams/force-layout/tree/v0.3.0.6) (2014-08-20)++[Full Changelog](https://github.com/diagrams/force-layout/compare/v0.3.0.5...v0.3.0.6)++## [v0.3.0.5](https://github.com/diagrams/force-layout/tree/v0.3.0.5) (2014-06-12)++[Full Changelog](https://github.com/diagrams/force-layout/compare/0_3_0_4...v0.3.0.5)++**Merged pull requests:**++- Make it compilable with GHC HEAD \(v7.9\) [\#1](https://github.com/diagrams/force-layout/pull/1) ([ggreif](https://github.com/ggreif))++## [v0.3.0.4]() (2 June 2014)++  - Allow lens-4.2++## [v0.3.0.3]() (19 March 2014)++  - Allow lens-4.1++## [v0.3.0.2] () (9 March 2014)++  - Allow vector-space-points-0.2++## [v0.3.0.1] () (12 February 2014)++  - Allow lens-4.0++## [v0.3]() [1 January 2014]++  - Use lenses for ForceLayoutOpts++## [v0.2.0.1] () (22 Dec 20130++  - Allow base-4.7++## [v0.2] () (5 December 2012)++  - Switch from fclabels to lens.++    Note this requires a major version bump because the accessors for+    Particle and Ensemble are exported, and they have completely+    different types.  But the API has not otherwise changed.++## [v0.1.0.2:] () (23 August 2012)++  - Bump upper bounds to allow base-4.6 and containers-0.5++## [v0.1.0.1] () (21 December 2011)++  - Bump fclabels upper bound to allow 1.1.0++## [v0.1.0.0] () (20 December 2011)++  - Initial release++\* *This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)*
− CHANGES
@@ -1,74 +0,0 @@-* 0.3.0.11 (2 April 2015)-- - allow lens-4.9- - allow vector-space-0.10--* 0.3.0.10 (12 March 2015)--- change category to Physics--* 0.3.0.9 (13 Jan 2015)--- Allow vector-space-0.9-- Allow lens-4.7--* 0.3.0.8 (17 November 2014)--- Allow lens-4.6--* 0.3.0.7 (22 August 2014)--- Allow lens-4.4--* 0.3.0.6 (20 August 2014)--  - Allow lens-4.3--* 0.3.0.5 (12 June 2014)--  - Add extension to allow building with GHC HEAD (7.9) (thanks to-    Gabor Greif)--* 0.3.0.4: 2 June 2014--  - Allow lens-4.2--* 0.3.0.3: 19 March 2014--  - Allow lens-4.1--* 0.3.0.2: 9 March 2014--  - Allow vector-space-points-0.2--* 0.3.0.1: 12 February 2014--  - Allow lens-4.0--* 0.3: 1 January 2014--  - Use lenses for ForceLayoutOpts--* 0.2.0.1: 22 Dec 2013--  - Allow base-4.7--* 0.2: 5 December 2012--  - Switch from fclabels to lens.--    Note this requires a major version bump because the accessors for-    Particle and Ensemble are exported, and they have completely-    different types.  But the API has not otherwise changed.--* 0.1.0.2: 23 August 2012--  - Bump upper bounds to allow base-4.6 and containers-0.5--* 0.1.0.1: 21 December 2011--  - Bump fclabels upper bound to allow 1.1.0--* 0.1.0.0: 20 December 2011--  - Initial release
force-layout.cabal view
@@ -1,5 +1,5 @@ name:                force-layout-version:             0.3.0.11+version:             0.4.0.0 synopsis:            Simple force-directed layout description:         Simulation engine for doing simple force-based layout,                      /e.g./ for trees or graphs.  See the diagrams-contrib package@@ -13,17 +13,17 @@ category:            Physics build-type:          Simple cabal-version:       >=1.10-extra-source-files:  CHANGES+extra-source-files:  CHANGELOG.md+tested-with:         GHC == 7.6.3, GHC == 7.8.4, GHC == 7.10.1 source-repository head   type:     git   location: git://github.com/diagrams/force-layout.git  library   exposed-modules:     Physics.ForceLayout-  build-depends:       base >= 4.2 && < 4.8,-                       vector-space >=0.7 && <0.11,-                       vector-space-points >= 0.1.1 && < 0.3,-                       lens >= 3 && < 4.10,+  build-depends:       base >= 4.2 && < 4.9,+                       linear >= 1.10 && < 1.19,+                       lens >= 3.0 && < 4.10,                        containers >=0.4 && < 0.6,                        data-default-class >= 0.0.1 && < 0.1   hs-source-dirs:      src
src/Physics/ForceLayout.hs view
@@ -1,8 +1,6 @@-{-# LANGUAGE FlexibleContexts     #-}-{-# LANGUAGE ScopedTypeVariables  #-}-{-# LANGUAGE TemplateHaskell      #-}-{-# LANGUAGE TypeFamilies         #-}-{-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TemplateHaskell     #-}+{-# LANGUAGE TypeFamilies        #-}  ----------------------------------------------------------------------------- -- |@@ -16,12 +14,14 @@ -- -- To use, just create an 'Ensemble' like so: --+-- > import           Control.Lens        ((&), (.~))+-- > import           Data.Default.Class  (def)+-- > import qualified Data.Map            as M+-- > import           Linear.Affine+-- > import           Linear.V2 -- > import           Physics.ForceLayout--- > import qualified Data.Map              as M--- > import           Data.AffineSpace.Point--- > import           Data.Default (def) -- >--- > e :: Ensemble (Double, Double)+-- > e :: Ensemble V2 Double -- > e = Ensemble [ (edges,    hookeForce 0.05 4) -- >              , (allPairs, coulombForce 1) -- >              ]@@ -29,7 +29,7 @@ -- >   where edges       = [(1,2), (2,3), (2,5), (3,5), (3,4), (4,5)] -- >         allPairs    = [(x,y) | x <- [1..4], y <- [x+1..5]] -- >         particleMap = M.fromList . zip [1..]--- >                     . map (initParticle . P)+-- >                     . map (initParticle . P . uncurry V2) -- >                     $ [ (2.0, 3.1), (6.3, 7.2) -- >                       , (0.3, 4.2), (1.6, -1.1) -- >                       , (4.8, 2.9)@@ -39,7 +39,7 @@ -- all intermediate states) or 'forceLayout' (to get only the ending -- state): ----- > e' :: Ensemble (Double, Double)+-- > e' :: Ensemble V2 Double -- > e' = forceLayout (def & damping     .~ 0.8 -- >                       & energyLimit .~ Just 0.001 -- >                       & stepLimit   .~ Nothing@@ -83,34 +83,34 @@         ) where -import           Data.AffineSpace-import           Data.AffineSpace.Point import           Data.Default.Class-import           Data.Foldable          (foldMap)-import qualified Data.Foldable          as F-import qualified Data.Map               as M+import qualified Data.Foldable      as F+import qualified Data.Map           as M import           Data.Monoid-import           Data.VectorSpace       hiding (Sum)  import           Control.Lens +import           Linear.Affine+import           Linear.Metric+import           Linear.Vector+ ------------------------------------------------------------ --  Particles ------------------------------------------------------------  -- | A particle has a current position, current velocity, and current --   force acting on it.-data Particle v = Particle { _pos   :: Point v-                           , _vel   :: v-                           , _force :: v-                           }-  deriving (Eq, Show)+data Particle v n = Particle { _pos   :: Point v n+                             , _vel   :: v n+                             , _force :: v n+                             }+  deriving Eq  makeLenses ''Particle  -- | Create an initial particle at rest at a particular location.-initParticle :: AdditiveGroup v => Point v -> Particle v-initParticle p = Particle p zeroV zeroV+initParticle :: (Additive v, Num n) => Point v n -> Particle v n+initParticle p = Particle p zero zero  ------------------------------------------------------------ --  Ensembles@@ -127,9 +127,9 @@ --   particles, and a list of forces that are operative.  Each force --   has a list of edges to which it applies, and is represented by a --   function giving the force between any two points.-data Ensemble v = Ensemble { _forces    :: [([Edge], Point v -> Point v -> v)]-                           , _particles :: M.Map PID (Particle v)-                           }+data Ensemble v n = Ensemble { _forces    :: [([Edge], Point v n -> Point v n -> v n)]+                             , _particles :: M.Map PID (Particle v n)+                             }  makeLenses ''Ensemble @@ -139,25 +139,28 @@  -- | Simulate one time step for an entire ensemble, with the given --   damping factor.-ensembleStep :: VectorSpace v => Scalar v -> Ensemble v -> Ensemble v+ensembleStep :: (Additive v, Num n) => n -> Ensemble v n -> Ensemble v n ensembleStep d = (over particles . M.map) (particleStep d) . recalcForces  -- | Simulate one time step for a particle (assuming the force acting --   on it has already been computed), with the given damping factor.-particleStep :: VectorSpace v => Scalar v -> Particle v -> Particle v+particleStep :: (Additive v, Num n) => n -> Particle v n -> Particle v n particleStep d = stepPos . stepVel   where stepVel p = vel .~ (d *^ (p^.vel ^+^ p^.force)) $ p         stepPos p = pos %~ (.+^ p^.vel) $ p  -- | Recalculate all the forces acting in the next time step of an --   ensemble.-recalcForces :: forall v. AdditiveGroup v => Ensemble v -> Ensemble v+recalcForces :: (Additive v, Num n) => Ensemble v n -> Ensemble v n recalcForces = calcForces . zeroForces-  where zeroForces = (particles %~) . M.map $ force .~ zeroV+  where zeroForces = (particles %~) . M.map $ force .~ zero         calcForces (Ensemble fs ps)           = Ensemble fs-            (ala Endo foldMap (concatMap (\(es, f) -> (map (mkForce f) es)) fs) ps)-        mkForce :: (Point v -> Point v -> v) -> Edge -> M.Map Int (Particle v) -> M.Map Int (Particle v)+            (ala Endo F.foldMap (concatMap (\(es, f) -> (map (mkForce f) es)) fs) ps)+        -- mkForce :: (Point v n -> Point v n -> v n)+        --         -> Edge+        --         -> M.Map Int (Particle v n)+        --         -> M.Map Int (Particle v n)         mkForce f (i1, i2) m           = case (M.lookup i1 m, M.lookup i2 m) of               (Just p1, Just p2) ->@@ -167,37 +170,37 @@               _                  -> m  -- | Compute the total kinetic energy of an ensemble.-kineticEnergy :: (InnerSpace v, Num (Scalar v)) => Ensemble v -> Scalar v-kineticEnergy = ala Sum F.foldMap . fmap (magnitudeSq . view vel) . view particles+kineticEnergy :: (Metric v, Num n) => Ensemble v n -> n+kineticEnergy = ala Sum F.foldMap . fmap (quadrance . view vel) . view particles  ------------------------------------------------------------ --  Simulation ------------------------------------------------------------  -- | Options for customizing a simulation.-data ForceLayoutOpts v =+data ForceLayoutOpts n =   FLOpts-  { _damping     :: Scalar v           -- ^ Damping factor to be-                                       --   applied at each step.-                                       --   Should be between 0 and 1.-                                       --   The default is 0.8.-  , _energyLimit :: Maybe (Scalar v)   -- ^ Kinetic energy below which-                                       --   simulation should stop.-                                       --   If @Nothing@, pay no-                                       --   attention to kinetic-                                       --   energy.  The default is-                                       --   @Just 0.001@.-  , _stepLimit   :: Maybe Int          -- ^ Maximum number of-                                       --   simulation steps.  If-                                       --   @Nothing@, pay no-                                       --   attention to the number of-                                       --   steps.  The default is-                                       --   @Just 1000@.+  { _damping     :: n         -- ^ Damping factor to be+                              --   applied at each step.+                              --   Should be between 0 and 1.+                              --   The default is 0.8.+  , _energyLimit :: Maybe n   -- ^ Kinetic energy below which+                              --   simulation should stop.+                              --   If @Nothing@, pay no+                              --   attention to kinetic+                              --   energy.  The default is+                              --   @Just 0.001@.+  , _stepLimit   :: Maybe Int -- ^ Maximum number of+                              --   simulation steps.  If+                              --   @Nothing@, pay no+                              --   attention to the number of+                              --   steps.  The default is+                              --   @Just 1000@.   }  makeLenses ''ForceLayoutOpts -instance Fractional (Scalar v) => Default (ForceLayoutOpts v) where+instance Fractional n => Default (ForceLayoutOpts n) where   def = FLOpts         { _damping     = 0.8         , _energyLimit = Just 0.001@@ -210,8 +213,8 @@ --   be infinite, if a 'stepLimit' is not specified and either the --   kinetic energy never falls below the specified threshold, or no --   energy threshold is specified.-simulate :: (InnerSpace v, Ord (Scalar v), Num (Scalar v))-         => ForceLayoutOpts v -> Ensemble v -> [Ensemble v]+simulate :: (Metric v, Num n, Ord n)+         => ForceLayoutOpts n -> Ensemble v n -> [Ensemble v n] simulate opts e   = (e:)   . takeWhile (maybe (const True) (<) (opts ^. energyLimit) . kineticEnergy)@@ -225,8 +228,8 @@ --   given), or the ensemble that results after a number of steps --   equal to the 'stepLimit' (if given), whichever comes first. --   Otherwise @forceLayout@ will not terminate.-forceLayout :: (InnerSpace v, Ord (Scalar v), Num (Scalar v))-            => ForceLayoutOpts v -> Ensemble v -> Ensemble v+forceLayout :: (Metric v, Num n, Ord n)+            => ForceLayoutOpts n -> Ensemble v n -> Ensemble v n forceLayout opts = last . simulate opts  ------------------------------------------------------------@@ -237,21 +240,18 @@ --   multiple of the unit vector in the direction from @p1@ to @p2@, --   given a function @f@ which computes the force's magnitude as a --   function of the distance between the points.-distForce :: (InnerSpace v, Floating (Scalar v))-          => (Scalar v -> Scalar v) -> Point v -> Point v -> v+distForce :: (Metric v, Floating n) => (n -> n) -> Point v n -> Point v n -> v n distForce f p1 p2 = withLength (f (distance p1 p2)) (p2 .-. p1)-  where withLength s v = s *^ normalized v+  where withLength s v = s *^ signorm v  -- | @hookeForce k l p1 p2@ computes the force on @p1@, assuming that --   @p1@ and @p2@ are connected by a spring with equilibrium length @l@ --   and spring constant @k@.-hookeForce :: (InnerSpace v, Floating (Scalar v))-           => Scalar v -> Scalar v -> Point v -> Point v -> v+hookeForce :: (Metric v, Floating n) => n -> n -> Point v n -> Point v n -> v n hookeForce k l = distForce (\d -> k * (d - l))  -- | @coulombForce k@ computes the electrostatic repulsive force --   between two charged particles, with constant of proportionality --   @k@.-coulombForce :: (InnerSpace v, Floating (Scalar v))-             => Scalar v -> Point v -> Point v -> v-coulombForce k = distForce (\d -> -k * 1/(d*d))+coulombForce :: (Metric v, Floating n) => n -> Point v n -> Point v n -> v n+coulombForce k = distForce (\d -> -k/(d*d))