ipa (empty) → 0.1.0.0
raw patch · 7 files changed
+1089/−0 lines, 7 filesdep +basedep +hspecdep +ipa
Dependencies added: base, hspec, ipa, text, unicode-transforms
Files
- CHANGELOG.org +2/−0
- LICENSE +30/−0
- README.org +60/−0
- ipa.cabal +56/−0
- src/Language/IPA.hs +588/−0
- src/Language/IPA/Types.hs +263/−0
- test/Main.hs +90/−0
+ CHANGELOG.org view
@@ -0,0 +1,2 @@+* 0.1.0.0++ Initial release
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright (c) 2021, Rory Tyler Hayford++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++ * Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.++ * Redistributions in binary form must reproduce the above+ copyright notice, this list of conditions and the following+ disclaimer in the documentation and/or other materials provided+ with the distribution.++ * Neither the name of Rory Tyler Hayford nor the names of other+ contributors may be used to endorse or promote products derived+ from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ README.org view
@@ -0,0 +1,60 @@+* ipa+** About+~ipa~ is a Haskell library for dealing with International Phonetic Alphabet (IPA) transcriptions. It provides a set of datatypes for working with speech segments and suprasegmentals which can be represented using IPA transcription.+** Usage+IPA values can be created by constructing ~Segment~ or ~Syllable~ values and applying ~toIPA~.+For instance:+#+begin_src haskell+{-# LANGUAGE PatternSynonyms #-}+{-# LANGUAGE OverloadedStrings #-}+ +import Language.IPA+import qualified Data.Text.IO as T++main :: IO () +main = maybe message (T.putStrLn . unIPA) (toIPA b)+ where+ b = PulmonicConsonant Voiced Bilabial Plosive+ message = T.putStrLn "Invalid or unrepresentable segment!"+ +#+end_src+~Segment~ and ~Syllable~ values can be adorned with additional articulatory information as well, and can further be nested to created more complex structures, e.g.:+#+begin_src haskell+someComplexVowel :: Segment+someComplexVowel = WithSegmentalFeature + (SuperScriptNumeric 255)+ (WithSegmentalFeature + (Length OverLong)+ (WithSegmentalFeature + Compressed+ (Vowel Close Back Unrounded)))+-- ɯᵝːː²⁵⁵ + +#+end_src+~IPA~ is an instance of ~Semigroup~, so values can be concatenated with ~<>~:+#+begin_src haskell+someSyllables :: Maybe IPA+someSyllables = (<>) <$> toIPA syllable1 <*> toIPA syllable2+ where+ syllable1 =+ WithSuprasegmentalFeature Linking+ (Syllable [ WithSegmentalFeature --+ (Length Long)+ (Vowel Close Back Rounded)+ ])++ syllable2 = Syllable [ PulmonicConsonant Voiced Palatal Approximant+ , Vowel OpenMid Front Unrounded+ , Vowel Mid Central Unrounded+ ]+-- uː‿jɛə ++#+end_src+~toIPA~ is a method of the ~ReprIPA~ typeclass; I decided a typeclass was best in order to allow users to create their own instances if the library-supplied ones were insufficient. You could create an instance, for example, for a hypothetical ~Mora~ datatype, etc...+** License+This library is distributed under the BSD 3-Clause revised license.+** TODO TODO+- [ ] Export constant values for common segments+- [ ] Convenience functions for wrapping IPA values in different trasncription delimiters (phonemic, phonetic, etc...)+- [ ] Support for XSampa transcription and IPA-XSampa conversion+- [ ] Parsing and validation of user-supplied IPA literals
+ ipa.cabal view
@@ -0,0 +1,56 @@+cabal-version: 2.4+name: ipa+version: 0.1.0.0+synopsis: Internal Phonetic Alphabet (IPA)+description:+ Types and tools for working with the International Phonetic Alphabet (IPA)++license: BSD-3-Clause+license-file: LICENSE+author: Rory Tyler Hayford+maintainer: rory.hayford@protonmail.com+copyright: (c) Rory Tyler Hayford, 2021+homepage: https://gitlab.com/ngua/ipa-hs/-/blob/master/README.org+category: language+extra-source-files:+ README.org+ CHANGELOG.org++source-repository head+ type: git+ location: https://gitlab.com/ngua/ipa-hs++common common-options+ ghc-options:+ -Wall -Wcompat -Widentities -Wincomplete-record-updates+ -Wincomplete-uni-patterns -Wpartial-fields -Wredundant-constraints++common common-extensions+ default-extensions: OverloadedStrings++library+ import: common-options, common-extensions+ build-depends:+ , base ^>=4.13.0.0+ , text ^>=1.2.4+ , unicode-transforms ^>=0.3.7++ exposed-modules:+ Language.IPA+ Language.IPA.Types++ hs-source-dirs: src+ default-language: Haskell2010++test-suite ipa-testsuite+ import: common-options, common-extensions+ type: exitcode-stdio-1.0+ hs-source-dirs: test+ build-depends:+ , base+ , hspec+ , ipa+ , text++ main-is: Main.hs+ default-language: Haskell2010
+ src/Language/IPA.hs view
@@ -0,0 +1,588 @@+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE ViewPatterns #-}++-- |+-- Module : Language.IPA+-- Copyright : (c) 2021 Rory Tyler Hayford+--+-- License : BSD-3-Clause+-- Maintainer : rory.hayford@protonmail.com+-- Stability : experimental+-- Portability : GHC+--+-- Working with IPA transcriptions+module Language.IPA+ ( module M+ -- * Converting to IPA representations+ , ReprIPA(..)+ ) where++import Data.Char ( digitToInt )+import Data.Text ( Text )+import qualified Data.Text as T++import Language.IPA.Types as M++-- | Entities representable through IPA transcription+class ReprIPA a where+ -- | Produces an 'IPA' transcription given a valid 'Segment'; a result+ -- of @Nothing@ indicates either an unattested-yet-possible segment, or one+ -- considered impossible+ toIPA :: a -> Maybe IPA++ -- | Partial function for creating an 'IPA'. Useful if you are certain that+ -- the sound in question is representable+ toIPA' :: a -> IPA+ toIPA' (toIPA -> Just x) = x+ toIPA' _ = error "Illegal/unrepresentable value"++instance Traversable t => ReprIPA (Syllable t) where+ toIPA = \case+ -- Syllable without any suprasegmental information+ Syllable ss+ | null ss -> Nothing+ | otherwise -> foldr1 (<>) <$> traverse toIPA ss+ WithSuprasegmentalFeature feature s ->+ withSuprasegmentalFeature s feature++instance ReprIPA Segment where+ toIPA = \case+ Zero -> mkJustIPA "∅"+ Consonant c -> consonant c+ v@Vowel {} -> vowel v+ WithSegmentalFeature feature s -> withSegmentalFeature s feature++mkJustIPA :: Text -> Maybe IPA+mkJustIPA = Just . mkIPA++mkIPAOp :: ReprIPA a => (b -> Maybe IPA) -> a -> b -> Maybe IPA+mkIPAOp f x y = (<>) <$> toIPA x <*> f y++withSuprasegmentalFeature+ :: Traversable t => Syllable t -> SuprasegmentalFeature -> Maybe IPA+withSuprasegmentalFeature s = \case+ -- Level tones, non-diacritic+ LevelLexicalTone tone -> mkIPAOp ipaTone s tone+ where+ ipaTone = \case+ ExtraHighTone -> mkJustIPA "˥"+ HighTone -> mkJustIPA "˦"+ MidTone -> mkJustIPA "˧"+ LowTone -> mkJustIPA "˨"+ ExtraLowTone -> mkJustIPA "˩"+ -- Down-step and up-step are represented with+ -- diacritics, not tone characters+ _ -> Nothing++ -- Level tones, diacritic. The text value inside the 'IPA' is a+ -- combining character+ LevelLexicalToneDiacritic tone -> mkIPAOp ipaTone s tone+ where+ ipaTone = \case+ ExtraHighTone -> mkJustIPA "\x030b" -- ◌̋+ HighTone -> mkJustIPA "\x0341" -- ◌́+ MidTone -> mkJustIPA "\x0304" -- ◌̄+ LowTone -> mkJustIPA "\x0340" -- ◌̀+ ExtraLowTone -> mkJustIPA "\x030f" -- ◌̏+ DownStep -> mkJustIPA "ꜜ"+ UpStep -> mkJustIPA "ꜛ"++ -- Tone contours, non-diacritic+ LexicalToneContour tone -> mkIPAOp ipaToneContour s tone+ where+ ipaToneContour = \case+ Rising -> mkJustIPA "˩˥"+ Falling -> mkJustIPA "˥˩"+ HighRising -> mkJustIPA "˧˥"+ LowRising -> mkJustIPA "˩˧"+ HighFalling -> mkJustIPA "˥˧"+ LowFalling -> mkJustIPA "˧˩"+ RisingFalling -> mkJustIPA "˧˦˨"+ FallingRising -> mkJustIPA "˧˨˦"+ GlobalRise -> mkJustIPA "↗"+ GlobalFall -> mkJustIPA "↙"++ -- Tone contours, diacritic+ LexicalToneContourDiacritic tone -> mkIPAOp ipaToneContour s tone+ where+ ipaToneContour = \case+ Rising -> mkJustIPA "\x0302" -- ◌̂+ Falling -> mkJustIPA "\x030c" -- ◌̌+ HighRising -> mkJustIPA "\x1dc9" -- ◌᷉+ LowRising -> mkJustIPA "\x1dc5" -- ◌᷅+ HighFalling -> mkJustIPA "\x1dc7" -- ◌᷇+ LowFalling -> mkJustIPA "\x1dc6" -- ◌᷆+ RisingFalling -> mkJustIPA "\x1dc8" -- ◌᷈+ FallingRising -> mkJustIPA "\x1dc9" -- ◌᷉+ -- 'GlobalRise' and 'GlobalFall' don't have+ -- diacritic representations+ _ -> Nothing++ -- Syllable stress+ Stress stress -> mkIPAOp ipaStress s stress+ where+ ipaStress Primary = mkJustIPA "ˈ"+ ipaStress Secondary = mkJustIPA "ˌ"++ -- Explicit syllable break+ Break -> (<>) <$> toIPA s <*> mkJustIPA "."++ -- Syllable non-break+ Linking -> (<>) <$> toIPA s <*> mkJustIPA "‿"++withSegmentalFeature :: Segment -> SegmentalFeature -> Maybe IPA+withSegmentalFeature s = \case+ Voicing v -> mkIPAOp ipaVoicing s v+ where+ ipaVoicing = \case+ Voiceless -> mkJustIPA "\x030a" -- ◌̊+ Voiced -> mkJustIPA "\x030c" -- ◌̌+ Length l -> mkIPAOp ipaLength s l+ where+ ipaLength = \case+ OverLong -> mkJustIPA "ːː"+ HalfLong -> mkJustIPA "ˑ"+ Long -> mkJustIPA "ː"+ Short -> mkJustIPA mempty+ ExtraShort -> mkJustIPA "\x0306" -- ◌ ̆+ SecondaryArticulation sa -> mkIPAOp secondaryArticulation s sa+ SuperScriptNumeric ns -> (<>) <$> toIPA s <*> mkJustIPA digits+ where+ digits = T.concat $ T.pack <$> (code . digitToInt <$> show ns)++ code = \case+ 0 -> "\x2070"+ 1 -> "\x00b9"+ 2 -> "\x00b2"+ 3 -> "\x00b3"+ 4 -> "\x2074"+ 5 -> "\x2075"+ 6 -> "\x2076"+ 7 -> "\x2077"+ 8 -> "\x2078"+ 9 -> "\x2079"+ _ -> mempty++ feature -> (<>) <$> toIPA s <*> case feature of+ Aspirated -> mkJustIPA "\x02b0" -- ◌ʰ+ MoreRounded -> mkJustIPA "\x0339" -- ◌̹+ LessRounded -> mkJustIPA "\x031c" -- ◌̜+ Advanced -> mkJustIPA "\x031f" -- ◌̟+ Retracted -> mkJustIPA "\x0320" -- ◌̠+ Centralized -> mkJustIPA "\x0308" -- ◌̈+ MidCentralized -> mkJustIPA "\x033d" -- ◌̽+ Compressed -> mkJustIPA "\x1d5d" -- ◌ᵝ+ Syllabic -> mkJustIPA "\x0329" -- ◌̩+ NonSyllabic -> mkJustIPA "\x032f" -- ◌̯+ Rhotacized -> mkJustIPA "\x02de" -- ◌˞+ BreathyVoice -> mkJustIPA "\x0324" -- ◌̤+ CreakyVoice -> mkJustIPA "\x0330" -- ◌̰+ LinguoLabialized -> mkJustIPA "\x033c" -- ◌̼+ Labialized -> mkJustIPA "\x02b7" -- ◌ʷ+ Palatalized -> mkJustIPA "\x02b2" -- ◌ʲ+ Velarized -> mkJustIPA "\x02e0" -- ◌ˠ+ Pharyngealized -> mkJustIPA "\x02e4" -- ◌ˤ+ Raised -> mkJustIPA "\x031d" -- ◌̝+ Lowered -> mkJustIPA "\x031e" -- ◌̞+ AdvancedTongueRoot -> mkJustIPA "\x0318" -- ◌̘+ RetractedTongueRoot -> mkJustIPA "\x0319" -- ◌̙+ Dentalized -> mkJustIPA "\x032a" -- ◌̪+ Apical -> mkJustIPA "\x033a" -- ◌̺+ Laminal -> mkJustIPA "\x033b" -- ◌̻+ Nasalized -> mkJustIPA "\x0303" -- ◌̃+ NasalRelease -> mkJustIPA "\x207f" -- ◌ⁿ+ LateralRelease -> mkJustIPA "\x02e1" -- ◌ˡ+ NoAudibleRelease -> mkJustIPA "\x031a" -- ◌̚+ _ -> mkJustIPA "" --++consonant :: Consonant -> Maybe IPA+consonant = \case+ -- Pulmonic consonants+ -- Bilabials+ Pulmonic Voiceless Bilabial Nasal -> mkJustIPA "m̥"+ Pulmonic Voiced Bilabial Nasal -> mkJustIPA "m"+ Pulmonic Voiced Bilabial Plosive -> mkJustIPA "b"+ Pulmonic Voiceless Bilabial Plosive -> mkJustIPA "p"+ Pulmonic Voiceless Bilabial (Affricate NonSibilant) -> mkJustIPA "p͡ɸ"+ Pulmonic Voiced Bilabial (Affricate NonSibilant) -> mkJustIPA "b͡β"+ Pulmonic Voiceless Bilabial (Fricative NonSibilant) -> mkJustIPA "ɸ"+ Pulmonic Voiced Bilabial (Fricative NonSibilant) -> mkJustIPA "β"+ Pulmonic Voiced Bilabial Flap -> mkJustIPA "ⱱ̟"+ Pulmonic Voiceless Bilabial Trill -> mkJustIPA "ʙ̥"+ Pulmonic Voiced Bilabial Trill -> mkJustIPA "ʙ"++ -- Labio-dentals+ Pulmonic Voiced LabioDental Nasal -> mkJustIPA "ɱ"+ Pulmonic Voiceless LabioDental Plosive -> mkJustIPA "p̪"+ Pulmonic Voiced LabioDental Plosive -> mkJustIPA "b̪"+ Pulmonic Voiceless LabioDental (Affricate NonSibilant) ->+ mkJustIPA "p̪͡f"+ Pulmonic Voiced LabioDental (Affricate NonSibilant) -> mkJustIPA "b̪͡v"+ Pulmonic Voiceless LabioDental (Fricative NonSibilant) -> mkJustIPA "f"+ Pulmonic Voiced LabioDental (Fricative NonSibilant) -> mkJustIPA "v"+ Pulmonic Voiced LabioDental Approximant -> mkJustIPA "ʋ"+ Pulmonic Voiced LabioDental Flap -> mkJustIPA "ⱱ"++ -- Linguo-labials+ Pulmonic Voiced LinguoLabial Nasal -> mkJustIPA "n̼"+ Pulmonic Voiceless LinguoLabial Plosive -> mkJustIPA "t̼"+ Pulmonic Voiced LinguoLabial Plosive -> mkJustIPA "d̼"+ Pulmonic Voiceless LinguoLabial (Fricative NonSibilant) ->+ mkJustIPA "θ̼ "+ Pulmonic Voiced LinguoLabial (Fricative NonSibilant) -> mkJustIPA "ð̼"+ Pulmonic Voiced LinguoLabial Flap -> mkJustIPA "ɾ̼"++ -- Dentals+ Pulmonic Voiceless Dental (Affricate NonSibilant) -> mkJustIPA "t̼͡θ"+ Pulmonic Voiced Dental (Affricate NonSibilant) -> mkJustIPA "d̼͡ð"+ Pulmonic Voiceless Dental (Fricative NonSibilant) -> mkJustIPA "θ"+ Pulmonic Voiced Dental (Fricative NonSibilant) -> mkJustIPA "ð"++ -- Alveolars+ Pulmonic Voiceless Alveolar Nasal -> mkJustIPA "n̥"+ Pulmonic Voiced Alveolar Nasal -> mkJustIPA "n"+ Pulmonic Voiceless Alveolar Plosive -> mkJustIPA "t"+ Pulmonic Voiced Alveolar Plosive -> mkJustIPA "d"+ Pulmonic Voiceless Alveolar (Affricate Sibilant) -> mkJustIPA "t͡s"+ Pulmonic Voiced Alveolar (Affricate Sibilant) -> mkJustIPA "d͡z"+ Pulmonic Voiceless Alveolar (Affricate NonSibilant) ->+ mkJustIPA "t͡ɹ̝̊"+ Pulmonic Voiced Alveolar (Affricate NonSibilant) -> mkJustIPA "d͡ɹ̝"+ Pulmonic Voiceless Alveolar (Fricative Sibilant) -> mkJustIPA "s"+ Pulmonic Voiced Alveolar (Fricative Sibilant) -> mkJustIPA "z"+ Pulmonic Voiced Alveolar Approximant -> mkJustIPA "ɹ"+ Pulmonic Voiceless Alveolar Flap -> mkJustIPA "ɾ̥"+ Pulmonic Voiced Alveolar Flap -> mkJustIPA "ɾ"+ Pulmonic Voiceless Alveolar Trill -> mkJustIPA "r"+ Pulmonic Voiced Alveolar Trill -> mkJustIPA "r̥"+ Pulmonic Voiceless Alveolar LateralAffricate -> mkJustIPA "tɬ"+ Pulmonic Voiced Alveolar LateralAffricate -> mkJustIPA "dɮ"+ Pulmonic Voiceless Alveolar LateralFricative -> mkJustIPA "ɬ"+ Pulmonic Voiced Alveolar LateralFricative -> mkJustIPA "ɮ"+ Pulmonic Voiced Alveolar LateralApproximant -> mkJustIPA "l"+ Pulmonic Voiceless Alveolar LateralFlap -> mkJustIPA "ɺ̥"+ Pulmonic Voiced Alveolar LateralFlap -> mkJustIPA "ɺ"++ -- Post-alveolars+ Pulmonic Voiceless PostAlveolar (Affricate Sibilant) -> mkJustIPA "t͡ʃ"+ Pulmonic Voiced PostAlveolar (Affricate Sibilant) -> mkJustIPA "d͡ʒ"+ Pulmonic Voiceless PostAlveolar (Affricate NonSibilant) ->+ mkJustIPA "tɹ̠̊˔"+ Pulmonic Voiced PostAlveolar (Affricate NonSibilant) ->+ mkJustIPA "d͡ɹ̠˔"+ Pulmonic Voiceless PostAlveolar (Fricative Sibilant) -> mkJustIPA "ʃ"+ Pulmonic Voiced PostAlveolar (Fricative Sibilant) -> mkJustIPA "ʒ"+ Pulmonic Voiceless PostAlveolar (Fricative NonSibilant) ->+ mkJustIPA "ɹ̠̊˔"+ Pulmonic Voiced PostAlveolar (Fricative NonSibilant) -> mkJustIPA "ɹ̠˔"++ -- Retroflexes+ Pulmonic Voiceless Retroflex Nasal -> mkJustIPA "ɳ̊"+ Pulmonic Voiced Retroflex Nasal -> mkJustIPA "ɳ"+ Pulmonic Voiceless Retroflex Plosive -> mkJustIPA "ʈ"+ Pulmonic Voiced Retroflex Plosive -> mkJustIPA "ɖ"+ Pulmonic Voiceless Retroflex (Affricate Sibilant) -> mkJustIPA "ʈ͡ʂ"+ Pulmonic Voiced Retroflex (Affricate Sibilant) -> mkJustIPA "ɖ͡ʐ"+ Pulmonic Voiceless Retroflex (Fricative Sibilant) -> mkJustIPA "ʂ"+ Pulmonic Voiced Retroflex (Fricative Sibilant) -> mkJustIPA "ʐ"+ Pulmonic Voiced Retroflex (Fricative NonSibilant) -> mkJustIPA "ɻ˔"+ Pulmonic Voiced Retroflex Approximant -> mkJustIPA "ɻ"+ Pulmonic Voiceless Retroflex Flap -> mkJustIPA "ɽ̊"+ Pulmonic Voiced Retroflex Flap -> mkJustIPA "ɽ"+ Pulmonic Voiceless Retroflex Trill -> mkJustIPA "ɽ̊r̥"+ Pulmonic Voiced Retroflex Trill -> mkJustIPA "ɽr"+ Pulmonic Voiceless Retroflex LateralAffricate -> mkJustIPA "ʈɭ̊˔"+ Pulmonic Voiced Retroflex LateralAffricate -> mkJustIPA "ɖɭ˔"+ Pulmonic Voiceless Retroflex LateralFricative -> mkJustIPA "ɭ̊˔"+ Pulmonic Voiced Retroflex LateralFricative -> mkJustIPA "ɭ˔"+ Pulmonic Voiced Retroflex LateralApproximant -> mkJustIPA "ɭ"+ Pulmonic Voiceless Retroflex LateralFlap -> mkJustIPA "ɭ̥̆"+ Pulmonic Voiced Retroflex LateralFlap -> mkJustIPA "ɭ̆"++ -- Palatals+ Pulmonic Voiceless Palatal Nasal -> mkJustIPA "ɲ̊"+ Pulmonic Voiced Palatal Nasal -> mkJustIPA "ɲ"+ Pulmonic Voiceless Palatal Plosive -> mkJustIPA "c"+ Pulmonic Voiced Palatal Plosive -> mkJustIPA "ɟ"+ Pulmonic Voiceless Palatal (Affricate Sibilant) -> mkJustIPA "t͡ɕ"+ Pulmonic Voiced Palatal (Affricate Sibilant) -> mkJustIPA "d͡ʑ"+ Pulmonic Voiceless Palatal (Affricate NonSibilant) -> mkJustIPA "c͡ç"+ Pulmonic Voiced Palatal (Affricate NonSibilant) -> mkJustIPA "ɟ͡ʝ"+ Pulmonic Voiceless Palatal (Fricative Sibilant) -> mkJustIPA "ɕ"+ Pulmonic Voiced Palatal (Fricative Sibilant) -> mkJustIPA "ʑ"+ Pulmonic Voiceless Palatal (Fricative NonSibilant) -> mkJustIPA "ç"+ Pulmonic Voiced Palatal (Fricative NonSibilant) -> mkJustIPA "ʝ"+ Pulmonic Voiced Palatal Approximant -> mkJustIPA "j"+ Pulmonic Voiceless Palatal LateralAffricate -> mkJustIPA "cʎ̝̊"+ Pulmonic Voiced Palatal LateralAffricate -> mkJustIPA "ɟʎ̝"+ Pulmonic Voiceless Palatal LateralFricative -> mkJustIPA "ʎ̝̊"+ Pulmonic Voiced Palatal LateralFricative -> mkJustIPA "ʎ̝"+ Pulmonic Voiced Palatal LateralApproximant -> mkJustIPA "ʎ"+ Pulmonic Voiced Palatal LateralFlap -> mkJustIPA "ʎ̆"++ -- Velars+ Pulmonic Voiceless Velar Nasal -> mkJustIPA "ŋ̊"+ Pulmonic Voiced Velar Nasal -> mkJustIPA "ŋ"+ Pulmonic Voiceless Velar Plosive -> mkJustIPA "k"+ Pulmonic Voiced Velar Plosive -> mkJustIPA "g"+ Pulmonic Voiceless Velar (Affricate NonSibilant) -> mkJustIPA "k͡x"+ Pulmonic Voiced Velar (Affricate NonSibilant) -> mkJustIPA "g͡ɣ"+ Pulmonic Voiceless Velar (Fricative NonSibilant) -> mkJustIPA "x"+ Pulmonic Voiced Velar (Fricative NonSibilant) -> mkJustIPA "ɣ"+ Pulmonic Voiced Velar Approximant -> mkJustIPA "ɰ"+ Pulmonic Voiceless Velar LateralAffricate -> mkJustIPA "kʟ̝̊"+ Pulmonic Voiced Velar LateralAffricate -> mkJustIPA "ɡʟ̝"+ Pulmonic Voiceless Velar LateralFricative -> mkJustIPA "ʟ̝̊"+ Pulmonic Voiced Velar LateralFricative -> mkJustIPA "ʟ̝"+ Pulmonic Voiced Velar LateralApproximant -> mkJustIPA "ʟ"+ Pulmonic Voiced Velar LateralFlap -> mkJustIPA "ʟ̆"++ -- Uvulars+ Pulmonic Voiced Uvular Nasal -> mkJustIPA "ɴ"+ Pulmonic Voiceless Uvular Plosive -> mkJustIPA "q"+ Pulmonic Voiced Uvular Plosive -> mkJustIPA "ɢ"+ Pulmonic Voiceless Uvular (Affricate NonSibilant) -> mkJustIPA "q͡χ"+ Pulmonic Voiced Uvular (Affricate NonSibilant) -> mkJustIPA "ɢ͡ʁ"+ Pulmonic Voiceless Uvular (Fricative NonSibilant) -> mkJustIPA "χ"+ Pulmonic Voiced Uvular (Fricative NonSibilant) -> mkJustIPA "ʁ"+ Pulmonic Voiced Uvular Flap -> mkJustIPA "ɢ̆"+ Pulmonic Voiceless Uvular Trill -> mkJustIPA "ʀ"+ Pulmonic Voiced Uvular Trill -> mkJustIPA "ʀ̥"+ Pulmonic Voiced Uvular LateralApproximant -> mkJustIPA "ʟ̠"++ -- Pharyngeals+ Pulmonic Voiceless Pharyngeal Plosive -> mkJustIPA "ʡ"+ Pulmonic Voiced Pharyngeal (Affricate NonSibilant) -> mkJustIPA "ʡ͡ʢ"+ Pulmonic Voiceless Pharyngeal (Fricative NonSibilant) -> mkJustIPA "ħ"+ Pulmonic Voiced Pharyngeal (Fricative NonSibilant) -> mkJustIPA "ʕ"+ Pulmonic Voiced Pharyngeal Flap -> mkJustIPA "̆ʡ̆"+ Pulmonic Voiceless Pharyngeal Trill -> mkJustIPA "ʜ"+ Pulmonic Voiced Pharyngeal Trill -> mkJustIPA "ʢ"++ -- Glottals+ Pulmonic Voiceless Glottal Plosive -> mkJustIPA "ʔ"+ Pulmonic Voiceless Glottal (Affricate NonSibilant) -> mkJustIPA "ʔ͡h"+ Pulmonic Voiceless Glottal (Fricative NonSibilant) -> mkJustIPA "h"+ Pulmonic Voiced Glottal (Fricative NonSibilant) -> mkJustIPA "ɦ"+ Pulmonic Voiced Glottal Approximant -> mkJustIPA "̆̆ʔ̞"++ -- Ejectives+ -- Bilabials+ Ejective Bilabial Plosive -> mkJustIPA "pʼ"+ Ejective Bilabial (Fricative NonSibilant) -> mkJustIPA "ɸʼ"++ -- Labio-dentals+ Ejective LabioDental (Affricate NonSibilant) -> mkJustIPA "p̪͡fʼ"+ Ejective LabioDental (Fricative NonSibilant) -> mkJustIPA "fʼ"++ -- Dentals+ Ejective Dental Plosive -> mkJustIPA "t̪ʼ"+ Ejective Dental (Affricate NonSibilant) -> mkJustIPA "t̪͡θʼ"+ Ejective Dental (Fricative NonSibilant) -> mkJustIPA "θʼ"++ -- Alveolars+ Ejective Alveolar Plosive -> mkJustIPA "tʼ"+ Ejective Alveolar (Affricate Sibilant) -> mkJustIPA "t͡sʼ"+ Ejective Alveolar (Fricative Sibilant) -> mkJustIPA "sʼ"+ Ejective Alveolar LateralAffricate -> mkJustIPA "t͡ɬʼ"+ Ejective Alveolar LateralFricative -> mkJustIPA "ɬʼ"++ -- Post-alveolars+ Ejective PostAlveolar (Affricate Sibilant) -> mkJustIPA "t͡ʃʼ"+ Ejective PostAlveolar (Fricative Sibilant) -> mkJustIPA "ʃʼ"++ -- Retroflexes+ Ejective Retroflex Plosive -> mkJustIPA "ʈʼ"+ Ejective Retroflex (Affricate Sibilant) -> mkJustIPA "ʈ͡ʂʼ"+ Ejective Retroflex (Fricative Sibilant) -> mkJustIPA "ʂʼ"++ -- Palatals+ Ejective Palatal Plosive -> mkJustIPA "cʼ"+ Ejective Palatal (Affricate Sibilant) -> mkJustIPA "t͡ɕʼ"+ Ejective Palatal (Fricative Sibilant) -> mkJustIPA "ɕʼ"+ Ejective Palatal LateralAffricate -> mkJustIPA "cʎ̝̊ʼ"++ -- Velars+ Ejective Velar Plosive -> mkJustIPA "kʼ"+ Ejective Velar (Affricate NonSibilant) -> mkJustIPA "k͡xʼ"+ Ejective Velar (Fricative NonSibilant) -> mkJustIPA "xʼ"+ Ejective Velar LateralAffricate -> mkJustIPA "kʟ̝̊ʼ"++ -- Uvulars+ Ejective Uvular Plosive -> mkJustIPA "qʼ"+ Ejective Uvular (Affricate NonSibilant) -> mkJustIPA "q͡χʼ"+ Ejective Uvular (Fricative NonSibilant) -> mkJustIPA "χʼ"++ -- Pharyngeals+ Ejective Pharyngeal Plosive -> mkJustIPA "ʡʼ "++ -- Implosives+ Implosive Voiceless Bilabial -> mkJustIPA "ƥ"+ Implosive Voiced Bilabial -> mkJustIPA "ɓ"+ Implosive Voiceless Dental -> mkJustIPA "ƭ̪"+ Implosive Voiced Dental -> mkJustIPA "ɗ̪"+ Implosive Voiceless Alveolar -> mkJustIPA "ɗ"+ Implosive Voiced Alveolar -> mkJustIPA "ƭ"+ Implosive Voiceless Retroflex -> mkJustIPA "ᶑ"+ Implosive Voiced Retroflex -> mkJustIPA "ƭ̢"+ Implosive Voiceless Palatal -> mkJustIPA "ƈ"+ Implosive Voiced Palatal -> mkJustIPA "ʄ"+ Implosive Voiceless Velar -> mkJustIPA "ƙ"+ Implosive Voiced Velar -> mkJustIPA "ɠ"+ Implosive Voiceless Uvular -> mkJustIPA "ʠ"+ Implosive Voiced Uvular -> mkJustIPA "ʛ"++ -- Clicks+ Click Bilabial -> mkJustIPA "ʘ"+ Click Dental -> mkJustIPA "ǀ"+ Click Alveolar -> mkJustIPA "ǃ"+ Click PostAlveolar -> mkJustIPA "ǁ" -- lateral click+ Click Palatal -> mkJustIPA "ǂ"++ -- Double articulation+ DoublyArticulated Voiced Bilabial Alveolar Nasal -> mkJustIPA "n͡m"+ DoublyArticulated Voiceless Bilabial Alveolar Plosive -> mkJustIPA "t͡p"+ DoublyArticulated Voiced Bilabial Alveolar Plosive -> mkJustIPA "d͡b"+ DoublyArticulated Voiced Bilabial Velar Nasal -> mkJustIPA "ŋ͡m"+ DoublyArticulated Voiceless Bilabial Velar Plosive -> mkJustIPA "k͡p"+ DoublyArticulated Voiced Bilabial Velar Plosive -> mkJustIPA "g͡b"+ DoublyArticulated Voiceless Uvular Pharyngeal Plosive -> mkJustIPA "q͡ʡ"+ DoublyArticulated Voiceless Bilabial Palatal (Fricative NonSibilant) ->+ mkJustIPA "ɥ̊"+ DoublyArticulated Voiced Bilabial Palatal Approximant -> mkJustIPA "ɥ"+ DoublyArticulated Voiceless Bilabial Velar (Fricative NonSibilant) ->+ mkJustIPA "ʍ"+ DoublyArticulated Voiced Bilabial Velar Approximant -> mkJustIPA "w"+ DoublyArticulated Voiced Alveolar Velar LateralApproximant ->+ mkJustIPA "ɫ"+ -- The sj-sound in Swedish phonology; actual realization is contested+ -- and appears to vary between dialects+ DoublyArticulated Voiceless PostAlveolar Velar (Fricative Sibilant) ->+ mkJustIPA "ɧ"+ DoublyArticulated Voiceless LabioDental Velar (Fricative Sibilant) ->+ mkJustIPA "ɧ"++ _ -> Nothing++vowel :: Segment -> Maybe IPA+vowel = \case+ Vowel Close Front Unrounded -> mkJustIPA "i"+ Vowel Close Front Rounded -> mkJustIPA "y"+ Vowel Close Central Unrounded -> mkJustIPA "ɨ"+ Vowel Close Central Rounded -> mkJustIPA "ʉ"+ Vowel Close Back Unrounded -> mkJustIPA "ɯ"+ Vowel Close Back Rounded -> mkJustIPA "u"+ Vowel NearClose Front Unrounded -> mkJustIPA "ɪ"+ Vowel NearClose Front Rounded -> mkJustIPA "ʏ"+ Vowel NearClose Back Rounded -> mkJustIPA "ʊ"+ Vowel CloseMid Front Unrounded -> mkJustIPA "e"+ Vowel CloseMid Front Rounded -> mkJustIPA "ø"+ Vowel CloseMid Central Unrounded -> mkJustIPA "ɘ"+ Vowel CloseMid Central Rounded -> mkJustIPA "ɵ"+ Vowel CloseMid Back Unrounded -> mkJustIPA "ɤ"+ Vowel CloseMid Back Rounded -> mkJustIPA "o"+ Vowel Mid Front Unrounded -> mkJustIPA "e̞"+ Vowel Mid Front Rounded -> mkJustIPA "ø̞"+ Vowel Mid Central Unrounded -> mkJustIPA "ə"+ Vowel Mid Central Rounded -> mkJustIPA "ə"+ Vowel Mid Back Unrounded -> mkJustIPA "ɤ̞"+ Vowel Mid Back Rounded -> mkJustIPA "o̞"+ Vowel OpenMid Front Unrounded -> mkJustIPA "ɛ"+ Vowel OpenMid Front Rounded -> mkJustIPA "œ"+ Vowel OpenMid Central Unrounded -> mkJustIPA "ɜ"+ Vowel OpenMid Central Rounded -> mkJustIPA "ɞ"+ Vowel OpenMid Back Unrounded -> mkJustIPA "ʌ"+ Vowel OpenMid Back Rounded -> mkJustIPA "ɔ"+ Vowel NearOpen Front Unrounded -> mkJustIPA "æ"+ Vowel NearOpen Central Unrounded -> mkJustIPA "ɐ"+ Vowel Open Front Unrounded -> mkJustIPA "a"+ Vowel Open Front Rounded -> mkJustIPA "ɶ"+ Vowel Open Central Unrounded -> mkJustIPA "ä"+ Vowel Open Back Unrounded -> mkJustIPA "ɑ"+ Vowel Open Back Rounded -> mkJustIPA "ɒ"+ _ -> Nothing++secondaryArticulation :: Segment -> Maybe IPA+secondaryArticulation = \case+ Consonant c -> case c of+ Pulmonic Voiced Bilabial Nasal -> mkJustIPA "\x1d50"+ Pulmonic Voiced LabioDental Nasal -> mkJustIPA "\x1dac"+ Pulmonic Voiced Alveolar Nasal -> mkJustIPA "\x207f"+ Pulmonic Voiced Retroflex Nasal -> mkJustIPA "\x1daf"+ Pulmonic Voiced Palatal Nasal -> mkJustIPA "\x1dae"+ Pulmonic Voiced Velar Nasal -> mkJustIPA "\x1d51"+ Pulmonic Voiced Uvular Nasal -> mkJustIPA "\x1db0"++ Pulmonic Voiced Bilabial Plosive -> mkJustIPA "\x1d56"+ Pulmonic Voiceless Bilabial Plosive -> mkJustIPA "\x1d47"+ Pulmonic Voiceless Alveolar Plosive -> mkJustIPA "\x1d57"+ Pulmonic Voiced Alveolar Plosive -> mkJustIPA "\x1d48"+ Pulmonic Voiceless Palatal Plosive -> mkJustIPA "\x1d9c"+ Pulmonic Voiced Palatal Plosive -> mkJustIPA "\x1da1"+ Pulmonic Voiceless Velar Plosive -> mkJustIPA "\x1d4f"+ Pulmonic Voiced Velar Plosive -> mkJustIPA "\x1da2"+ Pulmonic Voiceless Glottal Plosive -> mkJustIPA "\x02c0"++ Pulmonic Voiced Bilabial (Fricative NonSibilant) -> mkJustIPA "\x1db2"+ Pulmonic Voiceless Bilabial (Fricative NonSibilant) ->+ mkJustIPA "\x1d5d"+ Pulmonic Voiced LabioDental (Fricative NonSibilant) ->+ mkJustIPA "\x1da0"+ Pulmonic Voiceless LabioDental (Fricative NonSibilant) ->+ mkJustIPA "\x1d5b"+ Pulmonic Voiceless Dental (Fricative NonSibilant) -> mkJustIPA "\x1dbf"+ Pulmonic Voiced Dental (Fricative NonSibilant) -> mkJustIPA "\x1d9e"+ Pulmonic Voiceless Alveolar (Fricative Sibilant) -> mkJustIPA "\x02e2"+ Pulmonic Voiced Alveolar (Fricative Sibilant) -> mkJustIPA "\x1dbb"+ Pulmonic Voiceless PostAlveolar (Fricative Sibilant) ->+ mkJustIPA "\x1db4"+ Pulmonic Voiced PostAlveolar (Fricative Sibilant) -> mkJustIPA "\x1dbe"+ Pulmonic Voiceless Palatal (Fricative Sibilant) -> mkJustIPA "\x1d9d"+ Pulmonic Voiced Palatal (Fricative Sibilant) -> mkJustIPA "\x1dbd"+ Pulmonic Voiceless Palatal (Fricative NonSibilant) ->+ mkJustIPA "\x1d9c\x0327"+ Pulmonic Voiced Palatal (Fricative NonSibilant) -> mkJustIPA "\x1da8"+ Pulmonic Voiceless Velar (Fricative NonSibilant) -> mkJustIPA "\x02e3"+ Pulmonic Voiced Velar (Fricative NonSibilant) -> mkJustIPA "\x02e0"+ Pulmonic Voiceless Uvular (Fricative NonSibilant) -> mkJustIPA "\x1d61"+ Pulmonic Voiced Uvular (Fricative NonSibilant) -> mkJustIPA "\x02b6"+ Pulmonic Voiceless Glottal (Fricative NonSibilant) ->+ mkJustIPA "\x02b0"+ Pulmonic Voiced Glottal (Fricative NonSibilant) -> mkJustIPA "\x02b1"++ Pulmonic Voiced LabioDental Approximant -> mkJustIPA "\x1db9"+ Pulmonic Voiced Alveolar Approximant -> mkJustIPA "\x02b4"+ Pulmonic Voiced Retroflex Approximant -> mkJustIPA "\x02b5"+ Pulmonic Voiced Palatal Approximant -> mkJustIPA "\x02b2"+ Pulmonic Voiceless Velar Approximant -> mkJustIPA "\xab69"+ Pulmonic Voiced Velar Approximant -> mkJustIPA "\x1dad"++ Pulmonic Voiced Alveolar Trill -> mkJustIPA "\x02b3"++ _ -> Nothing++ Vowel Close Front Unrounded -> mkJustIPA "\x2071"+ Vowel Close Front Rounded -> mkJustIPA "\x02b8"+ Vowel Close Central Unrounded -> mkJustIPA "\x1da4"+ Vowel Close Central Rounded -> mkJustIPA "\x1db6"+ Vowel Close Back Unrounded -> mkJustIPA "\x1d5a"+ Vowel Close Back Rounded -> mkJustIPA "\x1d58"+ Vowel NearClose Front Unrounded -> mkJustIPA "\x1da6"+ Vowel NearClose Central Unrounded -> mkJustIPA "\x1da7"+ Vowel NearClose Back Rounded -> mkJustIPA "\x1db7"+ Vowel Mid Central Unrounded -> mkJustIPA "\x1d4a"+ Vowel Mid Central Rounded -> mkJustIPA "\x1d4a"+ Vowel OpenMid Front Unrounded -> mkJustIPA "\x1d4b"+ Vowel OpenMid Front Rounded -> mkJustIPA "\xa7f9"+ Vowel OpenMid Central Unrounded -> mkJustIPA "\x1d9f"+ Vowel OpenMid Back Unrounded -> mkJustIPA "\x1dba"+ Vowel OpenMid Back Rounded -> mkJustIPA "\x1d53"+ Vowel NearOpen Front Unrounded -> mkJustIPA "\x1d46"+ Vowel NearOpen Central Unrounded -> mkJustIPA "\x1d44"+ Vowel NearOpen Back Unrounded -> mkJustIPA "\x1d45"+ Vowel NearOpen Back Rounded -> mkJustIPA "\x1d9b"+ Vowel Open Front Unrounded -> mkJustIPA "\x1d43"+ Vowel Open Back Rounded -> mkJustIPA "\x1d44"++ _ -> Nothing+
+ src/Language/IPA/Types.hs view
@@ -0,0 +1,263 @@+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE PatternSynonyms #-}+{-# LANGUAGE StandaloneDeriving #-}+{-# LANGUAGE UndecidableInstances #-}++-- |+-- Module : Language.IPA.Types+-- Copyright : (c) 2021 Rory Tyler Hayford+--+-- License : BSD-3-Clause+-- Maintainer : rory.hayford@protonmail.com+-- Stability : experimental+-- Portability : GHC+--+-- Types representing segments representable in the IPA+module Language.IPA.Types+ ( -- * Notation systems+ IPA(..)+ , mkIPA+ , XSampa(XSampa)+ -- * Segments+ , Segment(..)+ -- ** Consonants (pulmonic and non-pulmonic)+ , Consonant(..)+ -- **** Convenience patterns+ -- $pat+ , pattern PulmonicConsonant+ , pattern EjectiveConsonant+ , pattern ClickConsonant+ , pattern ImplosiveConsonant+ -- *** Consonant features+ , Manner(..)+ , Place(..)+ , Phonation(..)+ , Sibilance(..)+ -- ** Vowel features+ , Height(..)+ , Backness(..)+ , Roundedness(..)+ -- * Suprasegmentals+ , Syllable(..)+ -- ** Suprasegmental features+ , SuprasegmentalFeature(..)+ , ToneContour(..)+ , LevelTone(..)+ , Stress(..)+ -- ** Segmental articulatory features+ , Length(..)+ , SegmentalFeature(..)+ ) where++import Data.Text ( Text )+import Data.Text.Normalize ( NormalizationMode(NFC), normalize )++import GHC.Generics ( Generic )++-- | Textual representation of a speech segment or grouping of segments, with+-- zero or more articulatory features; encoded in IPA transcription. Note this+-- has a 'Semigroup' instance, so various 'IPA's can conveniently be concatenated+-- with @<>@+newtype IPA = IPA { unIPA :: Text }+ deriving ( Show, Eq, Generic, Semigroup )++-- | Normalizes text value to NFC before wrapping it in 'IPA'. This is to ensure+-- the comparability of 'IPA' values+mkIPA :: Text -> IPA+mkIPA = IPA . normalize NFC++newtype XSampa = XSampa Text+ deriving ( Show, Eq, Generic )++-- | A single segment, or combination of a segment and articulatory feature+data Segment+ = Consonant Consonant -- ^ Pulmonic and non-pulmonic consonants+ | Vowel Height Backness Roundedness+ | Zero -- ^ A null/zero phone+ | WithSegmentalFeature SegmentalFeature Segment -- ^ Various other articulatory features+ deriving ( Show, Eq, Generic )++-- | Multiple segments, or combination of multiple segments with+-- suprasegmental feature+data Syllable t+ = Syllable (t Segment) -- ^ A grouping of segments+ | WithSuprasegmentalFeature SuprasegmentalFeature (Syllable t)+ -- ^ Articulatory features that affect/encompass the entire syllable+ deriving ( Generic )++deriving instance Show (t Segment) => Show (Syllable t)++deriving instance Eq (t Segment) => Eq (Syllable t)++-- | Pulmonic and non-pulmonic consonants+data Consonant+ = Pulmonic Phonation Place Manner+ | Ejective Place Manner+ | Implosive Phonation Place+ | Click Place+ | DoublyArticulated Phonation Place Place Manner+ deriving ( Show, Eq, Generic )++-- $pat+-- These are convenience patterns for creating different types of 'Consonant'+-- 'Segment's, as the nesting of data constructors might otherwise be somewhat+-- troublesome+pattern PulmonicConsonant :: Phonation -> Place -> Manner -> Segment+pattern PulmonicConsonant ph pl m = Consonant (Pulmonic ph pl m)++pattern EjectiveConsonant :: Place -> Manner -> Segment+pattern EjectiveConsonant pl m = Consonant (Ejective pl m)++pattern ClickConsonant :: Place -> Segment+pattern ClickConsonant pl = Consonant (Click pl)++pattern ImplosiveConsonant :: Phonation -> Place -> Segment+pattern ImplosiveConsonant ph pl = Consonant (Implosive ph pl)++-- | Consonantal manner of articulation+data Manner+ = Nasal+ | Plosive+ | Fricative Sibilance+ | Affricate Sibilance+ | Approximant+ | Flap+ | Trill+ | LateralAffricate+ | LateralFricative+ | LateralApproximant+ | LateralFlap+ deriving ( Show, Eq, Generic )++-- | Consonantal place of articulation+data Place+ = Bilabial+ | LabioDental+ | LinguoLabial+ | Dental+ | Alveolar+ | PostAlveolar+ | Retroflex+ | Palatal+ | Velar+ | Uvular+ | Pharyngeal+ | Glottal+ deriving ( Show, Eq, Generic, Ord )++-- | Phonation (voicing)+data Phonation = Voiced | Voiceless+ deriving ( Show, Eq, Generic )++-- | Sibilance for fricative consonants+data Sibilance = Sibilant | NonSibilant+ deriving ( Show, Eq, Generic )++-- | Vowel height+data Height = Close | NearClose | CloseMid | Mid | OpenMid | NearOpen | Open+ deriving ( Show, Eq, Generic )++-- | Vowel backness+data Backness = Front | NearFront | Central | NearBack | Back+ deriving ( Show, Eq, Generic, Ord )++-- | Vowel roundedness+data Roundedness = Rounded | Unrounded+ deriving ( Show, Eq, Generic )++-- | Lexical tone with Chao-style tone letters+data LevelTone+ = ExtraHighTone+ | HighTone+ | MidTone+ | LowTone+ | ExtraLowTone+ | DownStep+ | UpStep+ deriving ( Show, Eq, Generic, Ord )++-- | Lexical tone represented as a contour+data ToneContour+ = Rising+ | Falling+ | HighRising+ | LowRising+ | HighFalling+ | LowFalling+ | RisingFalling+ | FallingRising+ | GlobalRise+ | GlobalFall+ deriving ( Show, Eq, Generic, Ord )++-- | Vowel length; also serves as a notation for consonant gemination in the IPA+data Length+ = OverLong+ | HalfLong+ | Long+ | Short+ -- ^ The default/unmarked length; using this constructor doesn't affect the+ -- default IPA representation of the segment+ | ExtraShort+ deriving ( Show, Eq, Generic, Ord )++-- | Various articulatory features with a diacritic represenation in the IPA.+-- These can be combined with 'Segment's using the 'WithSegmentalFeature'+-- constructor of that type to produce a 'Segment' annotated with a given+-- articulatory feature, e.g.:+--+-- >>> toIPA $ WithSegmentalFeature (Length Long) (Vowel Close Front Unrounded)+-- Just (IPA "i\720") -- iː+data SegmentalFeature+ = Voicing Phonation+ | Length Length+ | SecondaryArticulation Segment+ | SuperScriptNumeric Int+ | Aspirated+ | MoreRounded+ | LessRounded+ | Advanced+ | Retracted+ | Centralized+ | MidCentralized+ | Compressed+ | Syllabic+ | NonSyllabic+ | Rhotacized+ | BreathyVoice+ | CreakyVoice+ | LinguoLabialized+ | Labialized+ | Palatalized+ | Velarized+ | Pharyngealized+ | Raised+ | Lowered+ | AdvancedTongueRoot+ | RetractedTongueRoot+ | Dentalized+ | Apical+ | Laminal+ | Nasalized+ | NasalRelease+ | LateralRelease+ | NoAudibleRelease+ deriving ( Show, Eq, Generic )++data Stress = Primary | Secondary+ deriving ( Show, Eq, Generic, Ord )++data SuprasegmentalFeature+ = LevelLexicalTone LevelTone -- ^ Level lexical tone+ | LevelLexicalToneDiacritic LevelTone+ -- ^ Level lexical tone, diactritic notation+ | LexicalToneContour ToneContour-- ^ Lexical tone as a contour+ | LexicalToneContourDiacritic ToneContour+ -- ^ Lexical tone as a contour, diacritic notation+ | Stress Stress+ | Break+ | Linking+ deriving ( Show, Eq, Generic )+
+ test/Main.hs view
@@ -0,0 +1,90 @@+{-# LANGUAGE PatternSynonyms #-}++-- |+module Main where++import Data.Foldable ( traverse_ )+import Data.Maybe ( isNothing )++import Language.IPA ( ReprIPA(toIPA', toIPA) )+import Language.IPA.Types+ ( Backness(..)+ , Height(..)+ , IPA(IPA)+ , Length(..)+ , Manner(..)+ , Phonation(..)+ , Place(..)+ , Roundedness(..)+ , Segment(..)+ , SegmentalFeature(..)+ , Sibilance(..)+ , Stress(Primary)+ , SuprasegmentalFeature(..)+ , Syllable(..)+ , ToneContour(..)+ , pattern ImplosiveConsonant+ , pattern PulmonicConsonant+ )++import Test.Hspec+ ( describe+ , hspec+ , it+ , shouldBe+ , shouldSatisfy+ )++{- HLINT ignore "Redundant do" -}+main :: IO ()+main = hspec $ do+ describe "Segments" $ do+ it "Rejects nonsense segments" $ do+ let phones = toIPA+ <$> [ PulmonicConsonant Voiceless+ Uvular+ (Fricative Sibilant)+ , PulmonicConsonant Voiced Velar Flap+ , PulmonicConsonant Voiced Pharyngeal Plosive+ , PulmonicConsonant Voiceless Glottal Trill+ , Vowel NearClose Central Unrounded+ , Vowel NearOpen Back Rounded+ ]+ traverse_ (`shouldSatisfy` isNothing) phones++ describe "Segmental features" $ do+ it "Correctly makes 'Short' a noop" $ do+ let vcfu = Vowel Close Front Unrounded+ i = toIPA' vcfu+ iShort = toIPA' $ WithSegmentalFeature (Length Short) vcfu++ i `shouldBe` iShort++ it "Chains articulatory features" $ do+ let vowel = Vowel Close Back Unrounded+ IPA chained = toIPA'+ $ WithSegmentalFeature (Length OverLong)+ (WithSegmentalFeature Compressed+ vowel)+ chained `shouldBe` "ɯᵝːː"++ describe "Suprasegmentals" $ do+ it "Preserves individual segments and order" $ do+ let segments = [ ImplosiveConsonant Voiced Bilabial+ , Vowel CloseMid Back Unrounded+ ]+ IPA syllable = toIPA' $ Syllable segments+ syllable `shouldBe` "ɓɤ"++ describe "Suprasegmental features" $ do+ it "Chains articulatory features" $ do+ let segments = [ PulmonicConsonant Voiced Alveolar Plosive+ , Vowel CloseMid Back Rounded+ ]+ syllable = Syllable segments+ tone = LexicalToneContour Rising+ IPA chained = toIPA'+ $ WithSuprasegmentalFeature --+ (Stress Primary)+ (WithSuprasegmentalFeature tone syllable)+ chained `shouldBe` "do˩˥ˈ"