packages feed

ipa-0.3: src/Language/IPA/Types.hs

{-# LANGUAGE ConstraintKinds #-}
{-# 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(..)
    , mkXSampa
      -- * Segments
    , Segment(..)
      -- ** Consonants (pulmonic and non-pulmonic)
    , Consonant(..)
      -- *** Convenience patterns
      -- $pat
    , pattern PulmonicConsonant
    , pattern EjectiveConsonant
    , pattern ClickConsonant
    , pattern ImplosiveConsonant
    , pattern DoublyArticulatedConsonant
      -- *** Consonant features
    , Manner(..)
    , Place(..)
    , Phonation(..)
    , Sibilance(..)
      -- ** Vowels
    , Vowel(..)
      -- *** Convenience patterns
    , pattern PureVowel
    , pattern Diphthong
    , pattern Triphthong
      -- *** Vowel features
    , Height(..)
    , Backness(..)
    , Roundedness(..)
      -- * Suprasegmentals
    , MultiSegment
    , Syllable(..)
      -- ** Suprasegmental features
    , SuprasegmentalFeature(..)
    , ToneContour(..)
    , LevelTone(..)
    , Stress(..)
      -- ** Segmental articulatory features
    , Length(..)
    , SegmentalFeature(..)
      -- * Errors
    , IPAException(..)
    ) where

import           Control.Exception   ( Exception )

import           Data.Char           ( isAscii )
import           Data.Text           ( Text )
import qualified Data.Text           as T
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
      -- ^ The 'Text' value should be 'normalize'd to 'NFC'
    }
    deriving ( Show, Eq, Generic, Semigroup )

-- | 'normalize's '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

-- | X-SAMPA is an ASCII encoding of the IPA (ca. 1993). Note that fewer
-- transcriptions are possible using X-SAMPA than the IPA, so certain valid
-- 'IPA' 'Segment's have no direct equivalence using 'XSampa'. As with 'IPA',
-- 'XSampa' is an instance of 'Semigroup'
newtype XSampa = XSampa
    { unXSampa :: Text
      -- ^ The wrapped 'Text' should only contain ASCII characters
    }
    deriving ( Show, Eq, Generic, Semigroup )

-- | Wraps a 'Text' value in 'XSampa', provided the text only contains ASCII
-- characters
mkXSampa :: Text -> Maybe XSampa
mkXSampa t
    | T.all isAscii t = Just $ XSampa t
    | otherwise = Nothing

-- | A single segment, or combination of a segment and articulatory feature
data Segment
    = Consonant Consonant -- ^ Pulmonic and non-pulmonic consonants
    | Vowel Vowel -- ^ Monoph-, diph-, and triphthongs
    | Zero -- ^ A null/zero phone
    | WithSegmentalFeature SegmentalFeature Segment -- ^ Various other articulatory features
    | Optional Segment
      -- ^ A segment that is conventionally surrounded by parentheses. This is not an
      -- official part of the IPA, but is nevertheless encountered fairly frequently
      -- in IPA notation in the wild
    deriving ( Show, Eq, Generic )

-- | Multiple segments, or combination of multiple segments with
-- suprasegmental feature
data Syllable t
    = Syllable (t Segment)
      -- ^ A grouping of segments without extra suprasegmental information
    | 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)

-- | Constraint synonym for syllable containers
type MultiSegment t = (Applicative t, Traversable t, Monoid (t Segment))

-- | Pulmonic and non-pulmonic consonants
data Consonant
    = Pulmonic Phonation Place Manner
    | Ejective Place Manner
    | Implosive Phonation Place
    | Click Place -- ^ 'PostAlveolar' place represents a lateral click
    | 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
-- tiresome
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)

pattern DoublyArticulatedConsonant
    :: Phonation -> Place -> Place -> Manner -> Segment
pattern DoublyArticulatedConsonant ph pl1 pl2 m =
    Consonant (DoublyArticulated ph pl1 pl2 m)

-- | 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 type. Note that this type does not prevent the construction of
-- non-sensical vowel values such as @Diphthong (Diphthong ...) (Diphthong ...)@
data Vowel
    = Pure Height Backness Roundedness
    | Diphthongized Vowel Vowel
    | Triphthongized Vowel Vowel Vowel
    deriving ( Show, Eq, Generic )

pattern PureVowel :: Height -> Backness -> Roundedness -> Segment
pattern PureVowel h b r = Vowel (Pure h b r)

pattern Diphthong :: Vowel -> Vowel -> Segment
pattern Diphthong v1 v2 = Vowel (Diphthongized v1 v2)

pattern Triphthong :: Vowel -> Vowel -> Vowel -> Segment
pattern Triphthong v1 v2 v3 = Vowel (Triphthongized v1 v2 v3)

-- | 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
    | 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 tones in Chao letters
    | LevelLexicalToneDiacritic LevelTone
      -- ^ Level lexical tones, diacritic. The tone is a combining character
    | LexicalToneContour ToneContour
      -- ^ Lexical tone contours in Chao letters
    | LexicalToneContourDiacritic ToneContour
      -- ^ Lexical tone contours, as diacritics. Each contour is a combining
      -- character
    | ToneNumber Int
    | Stress Stress -- ^ Syllable stress
    | Break -- ^ Explicit syllable break
    | Linking -- ^ Absence of a break
    deriving ( Show, Eq, Generic )

data IPAException = InvalidIPA Text | InvalidXSampa Text
    deriving ( Show, Eq, Generic )

instance Exception IPAException