isotope 0.4.0.0 → 0.5.0.0
raw patch · 7 files changed
+145/−6 lines, 7 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
+ Isotope: charge :: ToElementalComposition a => a -> Maybe Charge
+ Isotope.Ion: Deprotonated :: a -> Deprotonated a
+ Isotope.Ion: Mz :: Double -> Mz
+ Isotope.Ion: Negative :: Polarity
+ Isotope.Ion: Positive :: Polarity
+ Isotope.Ion: Protonated :: a -> Protonated a
+ Isotope.Ion: [getMz] :: Mz -> Double
+ Isotope.Ion: class ToElementalComposition a => Ion a where mz a = Mz . abs $ monoisotopicMass' / charge' where monoisotopicMass' = getMonoisotopicMass $ monoisotopicMass a charge' = let charge'' = fromMaybe 0 (charge a) in if charge'' /= 0 then fromIntegral charge'' else error "An ion can't have a charge of 0!" polarity a = polarity' $ fromMaybe 0 (charge a) where polarity' c | c > 0 = Positive | c < 0 = Negative | c == 0 = error "An ion can't have a charge of 0!"
+ Isotope.Ion: data Polarity
+ Isotope.Ion: doublyDeprotonated :: a -> Deprotonated (Deprotonated a)
+ Isotope.Ion: doublyProtonated :: a -> Protonated (Protonated a)
+ Isotope.Ion: instance GHC.Classes.Eq Isotope.Ion.Mz
+ Isotope.Ion: instance GHC.Classes.Eq Isotope.Ion.Polarity
+ Isotope.Ion: instance GHC.Classes.Eq a => GHC.Classes.Eq (Isotope.Ion.Deprotonated a)
+ Isotope.Ion: instance GHC.Classes.Eq a => GHC.Classes.Eq (Isotope.Ion.Protonated a)
+ Isotope.Ion: instance GHC.Classes.Ord Isotope.Ion.Mz
+ Isotope.Ion: instance GHC.Classes.Ord Isotope.Ion.Polarity
+ Isotope.Ion: instance GHC.Classes.Ord a => GHC.Classes.Ord (Isotope.Ion.Deprotonated a)
+ Isotope.Ion: instance GHC.Classes.Ord a => GHC.Classes.Ord (Isotope.Ion.Protonated a)
+ Isotope.Ion: instance GHC.Read.Read Isotope.Ion.Mz
+ Isotope.Ion: instance GHC.Read.Read Isotope.Ion.Polarity
+ Isotope.Ion: instance GHC.Read.Read a => GHC.Read.Read (Isotope.Ion.Deprotonated a)
+ Isotope.Ion: instance GHC.Read.Read a => GHC.Read.Read (Isotope.Ion.Protonated a)
+ Isotope.Ion: instance GHC.Show.Show Isotope.Ion.Mz
+ Isotope.Ion: instance GHC.Show.Show Isotope.Ion.Polarity
+ Isotope.Ion: instance GHC.Show.Show a => GHC.Show.Show (Isotope.Ion.Deprotonated a)
+ Isotope.Ion: instance GHC.Show.Show a => GHC.Show.Show (Isotope.Ion.Protonated a)
+ Isotope.Ion: instance Isotope.Base.ToElementalComposition a => Isotope.Base.ToElementalComposition (Isotope.Ion.Deprotonated a)
+ Isotope.Ion: instance Isotope.Base.ToElementalComposition a => Isotope.Base.ToElementalComposition (Isotope.Ion.Protonated a)
+ Isotope.Ion: instance Isotope.Base.ToElementalComposition a => Isotope.Ion.Ion (Isotope.Ion.Deprotonated a)
+ Isotope.Ion: instance Isotope.Base.ToElementalComposition a => Isotope.Ion.Ion (Isotope.Ion.Protonated a)
+ Isotope.Ion: mz :: Ion a => a -> Mz
+ Isotope.Ion: newtype Deprotonated a
+ Isotope.Ion: newtype Mz
+ Isotope.Ion: newtype Protonated a
+ Isotope.Ion: polarity :: Ion a => a -> Polarity
Files
- README.md +34/−3
- isotope.cabal +3/−1
- src/Isotope/Base.hs +9/−1
- src/Isotope/Ion.hs +70/−0
- test/Isotope/BaseSpec.hs +5/−1
- test/Isotope/IonSpec.hs +22/−0
- test/Spec.hs +2/−0
README.md view
@@ -1,5 +1,5 @@ [](https://travis-ci.org/Michaelt293/isotope)-[](https://gitter.im/Michaelt293/isotope)+[](https://gitter.im/Michaelt293/isotope)  @@ -13,6 +13,7 @@ * [ToElementalComposition type class](#elementalcomposition-type-class) * [Behaviour of ElementalComposition, MolecularFormula, CondensedFormula and EmpiricalFormula data types](#behaviour-of-elementalcomposition-molecularformula-condensedformula-and-empiricalformula-data-types) * [Additional functions accepting an ElementSymbol as input](#additional-functions-accepting-an-elementsymbol-as-input)+ * [Representing ions in Isotope](#representing-ions-in-isotope) * [Comparison to other chemistry libraries](#comparison-to-other-chemistry-libraries) * [Radium](#radium) * [Ouch](#ouch)@@ -108,13 +109,13 @@ ### `ToElementalComposition` type class -`ToElementalComposition` is a superclass of `ToMolecularFormula`, `ToCondensedFormula` and `ToEmpiricalFormula`. In addition to the `toElementalComposition` method, the `ToElementalComposition` type class has three other methods; `monoisotopicMass`, `nominalMass` and `averageMass`. (`toElementalComposition` is the minimal complete definition.) `ElementSymbol`, `ElementalComposition`, `MolecularFormula`, `CondensedFormula` and `EmpiricalFormula` all have instances of `ToElementalComposition`. This provides a uniform approach to working with elements, elemental compositions, molecular formulae, condensed formulae and empirical formulae.+`ToElementalComposition` is a superclass of `ToMolecularFormula`, `ToCondensedFormula` and `ToEmpiricalFormula`. In addition to the `toElementalComposition` method, the `ToElementalComposition` type class has four other methods; `charge`, `monoisotopicMass`, `nominalMass` and `averageMass`. (`toElementalComposition` and `charge` is the minimal complete definition.) `ElementSymbol`, `ElementalComposition`, `MolecularFormula`, `CondensedFormula` and `EmpiricalFormula` all have instances of `ToElementalComposition`. This provides a uniform approach to working with elements, elemental compositions, molecular formulae, condensed formulae and empirical formulae. ```haskell ghci> nominalMass C NominalMass {getNominalMass = 12} ghci> averageMass [mol|CH4|] AverageMass {getAverageMass = 16.042498912958358}-ghci> monoisotopicMass [mol|N(CH3)3|]+ghci> monoisotopicMass [con|N(CH3)3|] MonoisotopicMass {getMonoisotopicMass = 59.073499294499996} ``` @@ -156,6 +157,36 @@ ```haskell ghci> isotopicMasses Ti [IsotopicMass {getIsotopicMass = 45.95262772},IsotopicMass {getIsotopicMass = 46.95175879},IsotopicMass {getIsotopicMass = 47.94794198},IsotopicMass {getIsotopicMass = 48.94786568},IsotopicMass {getIsotopicMass = 49.94478689}]+```++### Representing ions in Isotope++Ions are represented in `Isotope` using the `Ion` type class. The `Ion` type class has two methods, `mz` and `polarity`; where `mz` is mass-to-charge ratio and `polarity` is either `Positive` or `Negative`. Any type with an `ToElementalComposition` instance can have an `Ion` instance if charge is not equal to zero. If charge is equal to zero, a runtime exception will occur! Ideally, the type system should be put better use to catch this error at compile-time.++```haskell+data Ammonium = Ammonium deriving Show++instance ToElementalComposition Ammonium where+ toElementalComposition _ = mkElementalComposition [(N, 1), (H, 4)]+ charge _ = 1++instance Ion Ammonium++ghci> mz Ammonium+Mz {getMz = 18.03437413335}+```++`Protonated` and `Deprotonated` types, with `Ion` instances, are provided to represent protonated and deprotonated ions, respectively.++```haskell+ghci> mz . Protonated $ mkMolecularFormula [(H, 2), (O, 1)]+Mz {getMz = 19.01838971626}+ghci> mz . Deprotonated $ mkMolecularFormula [(H, 2), (O, 1)]+Mz {getMz = 17.0027396518}+ghci> polarity . Protonated $ mkMolecularFormula [(H, 2), (O, 1)]+Positive+ghci> polarity . Deprotonated $ mkMolecularFormula [(H, 2), (O, 1)]+Negative ``` ## Comparison to other chemistry libraries
isotope.cabal view
@@ -1,5 +1,5 @@ name: isotope-version: 0.4.0.0+version: 0.5.0.0 synopsis: Isotopic masses and relative abundances. description: Please see README.md homepage: https://github.com/Michaelt293/Element-isotopes/blob/master/README.md@@ -18,6 +18,7 @@ exposed-modules: Isotope , Isotope.Base , Isotope.Parsers+ , Isotope.Ion build-depends: base >= 4.7 && < 5 , containers >= 0.5 && < 0.6 , megaparsec >= 5 && < 6@@ -37,5 +38,6 @@ , megaparsec other-modules: Isotope.BaseSpec , Isotope.ParsersSpec+ , Isotope.IonSpec ghc-options: -threaded -rtsopts -with-rtsopts=-N default-language: Haskell2010
src/Isotope/Base.hs view
@@ -189,6 +189,8 @@ -- neutron number) for an isotope. type MassNumber = Int +type Charge = Int+ -------------------------------------------------------------------------------- -- 'Isotope' and 'Element' data types@@ -638,13 +640,14 @@ -- 'monoisotopicMass', 'nominalMass' and 'averageMass'. class ToElementalComposition a where toElementalComposition :: a -> ElementalComposition+ charge :: a -> Maybe Charge monoisotopicMass :: a -> MonoisotopicMass nominalMass :: a -> NominalMass averageMass :: a -> AverageMass monoisotopicMass = getFormulaSum elementMonoisotopicMass nominalMass = getFormulaSum elementNominalMass averageMass = getFormulaSum elementAverageMass- {-# MINIMAL (toElementalComposition) #-}+ {-# MINIMAL (toElementalComposition, charge) #-} -- Helper function for the calculating monoistopic masses, average mass and -- nominal masses for molecular formulae.@@ -672,9 +675,11 @@ instance ToElementalComposition ElementSymbol where toElementalComposition sym = mkElementalComposition [(sym, 1)]+ charge _ = Nothing instance ToElementalComposition ElementalComposition where toElementalComposition = id+ charge _ = Nothing instance Formula ElementalComposition where renderFormula f = foldMap renderFoldfunc@@ -742,6 +747,7 @@ instance ToElementalComposition MolecularFormula where toElementalComposition (MolecularFormula m) = ElementalComposition m+ charge _ = Nothing instance Formula MolecularFormula where renderFormula f = foldMap renderFoldfunc@@ -766,6 +772,7 @@ instance ToElementalComposition CondensedFormula where toElementalComposition = ElementalComposition . getMolecularFormula . toMolecularFormula+ charge _ = Nothing instance ToMolecularFormula CondensedFormula where toMolecularFormula c = foldMap foldFunc (getCondensedFormula c)@@ -814,6 +821,7 @@ instance ToElementalComposition EmpiricalFormula where toElementalComposition (EmpiricalFormula a) = ElementalComposition a+ charge _ = Nothing instance Formula EmpiricalFormula where renderFormula f = foldMap renderFoldfunc
+ src/Isotope/Ion.hs view
@@ -0,0 +1,70 @@+{-|+Module : Isotope.Ion+Description : Provides support for ions.+Copyright : Michael Thomas+License : GPL-3+Maintainer : Michael Thomas <Michaelt293@gmail.com>+Stability : Experimental++This module allows the mass-to-charge ratio and polarity of ions to be+calculated.+-}+module Isotope.Ion where++import Isotope.Base+import Data.Maybe (fromMaybe)+import Data.Monoid++-- | The polarity of a charge. A charge can be either `Positive` or `Negative`.+data Polarity = Positive | Negative+ deriving (Show, Read, Eq, Ord)++-- | The mass-to-charge ratio of an ion.+newtype Mz = Mz { getMz :: Double }+ deriving (Show, Read, Eq, Ord)++-- | The `Ion` type class. This type class has two methods: `mz` and `polarity`.+class ToElementalComposition a => Ion a where+ mz :: a -> Mz+ polarity :: a -> Polarity+ mz a = Mz . abs $ monoisotopicMass' / charge'+ where+ monoisotopicMass' = getMonoisotopicMass $ monoisotopicMass a+ charge' = let charge'' = fromMaybe 0 (charge a)+ in if charge'' /= 0+ then fromIntegral charge''+ else error "An ion can't have a charge of 0!"+ polarity a = polarity' $ fromMaybe 0 (charge a)+ where+ polarity' c+ | c > 0 = Positive+ | c < 0 = Negative+ | c == 0 = error "An ion can't have a charge of 0!"++-- | Protonated represents a protonated ion.+newtype Protonated a = Protonated a deriving (Show, Read, Eq, Ord)++instance ToElementalComposition a => ToElementalComposition (Protonated a) where+ toElementalComposition (Protonated a) = toElementalComposition a |+|+ mkElementalComposition [(H, 1)]+ charge (Protonated a) = getSum <$> Just (Sum 1) <> (Sum <$> charge a)++instance ToElementalComposition a => Ion (Protonated a)++-- | `doublyProtonated` takes a type and returns a doubly `Protonated` ion.+doublyProtonated :: a -> Protonated (Protonated a)+doublyProtonated = Protonated . Protonated++-- | `Deprotonated` represents a deprotonated ion.+newtype Deprotonated a = Deprotonated a deriving (Show, Read, Eq, Ord)++instance ToElementalComposition a => ToElementalComposition (Deprotonated a) where+ toElementalComposition (Deprotonated a) = toElementalComposition a |-|+ mkElementalComposition [(H, 1)]+ charge (Deprotonated a) = getSum <$> Just (Sum (-1)) <> (Sum <$> charge a)++instance ToElementalComposition a => Ion (Deprotonated a)++-- | `doublyDeprotonated` takes a type and returns a doubly `Deprotonated` ion.+doublyDeprotonated :: a -> Deprotonated (Deprotonated a)+doublyDeprotonated = Deprotonated . Deprotonated
test/Isotope/BaseSpec.hs view
@@ -115,6 +115,8 @@ describe "ToElementalComposition - ElementalComposition instance" $ do it "toElementalComposition" . property $ \ec -> toElementalComposition ec == (ec :: ElementalComposition)+ it "charge of an elemental composition should Just 0" . property $+ \ec -> charge (ec :: ElementalComposition) == Nothing it "monoisotopic mass of ethanol" $ withinTolerance (getMonoisotopicMass (monoisotopicMass [ele|C2H6O|])) 46.04186 0.0001 `shouldBe` True@@ -130,9 +132,11 @@ it "should give the correct formula" $ mkElementalComposition [(C, 2), (H, 6), (O, 1)] `shouldBe` [ele|C2H6O|] - describe "ToElementalComposition - ElementSymbol instance" .+ describe "ToElementalComposition - ElementSymbol instance" $ do it "monoisotopicMass" . property $ \sym -> monoisotopicMass sym == monoisotopicMass (mkElementalComposition [(sym, 1)])+ it "charge of a symbol should be Just 0" . property $+ \sym -> charge (sym :: ElementSymbol) == Nothing describe "Monoid instance for MolecularFormula" $ do it "associativity" . property $
+ test/Isotope/IonSpec.hs view
@@ -0,0 +1,22 @@+module Isotope.IonSpec (spec) where++import Isotope+import Isotope.Ion+import Test.Hspec++spec :: Spec+spec = do+ describe "mz" $ do+ it "The mass-to-charge ratio of protonated water should be 19.01838971626" $+ mz (Protonated water) `shouldBe` Mz {getMz = 19.01838971626}+ it "The mass-to-charge ratio of deprotonated water should be 17.0027396518" $+ mz (Deprotonated water) `shouldBe` Mz {getMz = 17.0027396518}++ describe "polarity" $ do+ it "The polarity of protonated water should be Positive" $+ polarity (Protonated water) `shouldBe` Positive+ it "The polarity of deprotonated water should be Negative" $+ polarity (Deprotonated water) `shouldBe` Negative++water :: MolecularFormula+water = mkMolecularFormula [(H, 2), (O, 1)]
test/Spec.hs view
@@ -4,8 +4,10 @@ import Test.QuickCheck import Isotope.BaseSpec import Isotope.ParsersSpec+import Isotope.IonSpec main :: IO () main = hspec $ do describe "Base" Isotope.BaseSpec.spec describe "Parsers" Isotope.ParsersSpec.spec+ describe "Ion" Isotope.IonSpec.spec