packages feed

hist-pl-lexicon 0.4.0 → 0.5.0

raw patch · 9 files changed

+232/−823 lines, 9 filesdep +hist-pl-dawgdep +hist-pl-typesdep +lazy-iodep −mtldep −polysoupdep −text-binaryPVP ok

version bump matches the API change (PVP)

Dependencies added: hist-pl-dawg, hist-pl-types, lazy-io

Dependencies removed: mtl, polysoup, text-binary

API changes (from Hackage documentation)

- NLP.HistPL.Dict: Key :: Text -> i -> Key i
- NLP.HistPL.Dict: Lex :: Key i -> Val a Text b -> Lex i a b
- NLP.HistPL.Dict: Rule :: !Int -> !Text -> Rule
- NLP.HistPL.Dict: Val :: a -> Map w b -> Val a w b
- NLP.HistPL.Dict: apply :: Rule -> Text -> Text
- NLP.HistPL.Dict: between :: Text -> Text -> Rule
- NLP.HistPL.Dict: cut :: Rule -> !Int
- NLP.HistPL.Dict: data Key i
- NLP.HistPL.Dict: data Lex i a b
- NLP.HistPL.Dict: data Rule
- NLP.HistPL.Dict: data Val a w b
- NLP.HistPL.Dict: decode :: Ord i => Text -> Node i a b -> LexSet i a b
- NLP.HistPL.Dict: entries :: Ord i => Dict i a b -> [Lex i a b]
- NLP.HistPL.Dict: forms :: Val a w b -> Map w b
- NLP.HistPL.Dict: fromList :: (Ord i, Ord a, Ord b) => [(Text, i, a, Text, b)] -> Dict i a b
- NLP.HistPL.Dict: info :: Val a w b -> a
- NLP.HistPL.Dict: instance (Eq a, Eq w, Eq b) => Eq (Val a w b)
- NLP.HistPL.Dict: instance (Eq i, Eq a, Eq b) => Eq (Lex i a b)
- NLP.HistPL.Dict: instance (Ord a, Ord w, Ord b) => Ord (Val a w b)
- NLP.HistPL.Dict: instance (Ord i, Ord a, Ord b) => Ord (Lex i a b)
- NLP.HistPL.Dict: instance (Ord w, Binary a, Binary w, Binary b) => Binary (Val a w b)
- NLP.HistPL.Dict: instance (Show a, Show w, Show b) => Show (Val a w b)
- NLP.HistPL.Dict: instance (Show i, Show a, Show b) => Show (Lex i a b)
- NLP.HistPL.Dict: instance Binary Rule
- NLP.HistPL.Dict: instance Eq Rule
- NLP.HistPL.Dict: instance Eq i => Eq (Key i)
- NLP.HistPL.Dict: instance Ord Rule
- NLP.HistPL.Dict: instance Ord i => Ord (Key i)
- NLP.HistPL.Dict: instance Show Rule
- NLP.HistPL.Dict: instance Show i => Show (Key i)
- NLP.HistPL.Dict: lexKey :: Lex i a b -> Key i
- NLP.HistPL.Dict: lexVal :: Lex i a b -> Val a Text b
- NLP.HistPL.Dict: lookup :: Ord i => Text -> Dict i a b -> LexSet i a b
- NLP.HistPL.Dict: mkLexSet :: Ord i => [Lex i a b] -> LexSet i a b
- NLP.HistPL.Dict: path :: Key i -> Text
- NLP.HistPL.Dict: revDict :: (Ord i, Ord a, Ord b) => Dict i a b -> Dict i a b
- NLP.HistPL.Dict: suffix :: Rule -> !Text
- NLP.HistPL.Dict: toList :: (Ord i, Ord a, Ord b) => Dict i a b -> [(Text, i, a, Text, b)]
- NLP.HistPL.Dict: type Dict i a b = DAWG Char () (Node i a b)
- NLP.HistPL.Dict: type LexSet i a b = Map (Key i) (Val a Text b)
- NLP.HistPL.Dict: type Node i a b = Map i (Val a Rule b)
- NLP.HistPL.Dict: uid :: Key i -> i
- NLP.HistPL.Dict: unLexSet :: LexSet i a b -> [Lex i a b]
- NLP.HistPL.LMF.Parse: parseLMF :: Text -> [LexEntry]
- NLP.HistPL.LMF.Parse: parseLexEntry :: Text -> LexEntry
- NLP.HistPL.LMF.Parse: readLMF :: FilePath -> IO [LexEntry]
- NLP.HistPL.LMF.Show: showLMF :: [LexEntry] -> Text
- NLP.HistPL.LMF.Show: showLexEntry :: LexEntry -> Text
- NLP.HistPL.Lexicon: getIndex :: HistPL -> IO [Key]
- NLP.HistPL.Lexicon: save :: FilePath -> [(LexEntry, Set Text)] -> IO (HistPL)
- NLP.HistPL.Lexicon: tryWithKey :: HistPL -> Key -> IO (Maybe LexEntry)
- NLP.HistPL.Lexicon: withKey :: HistPL -> Key -> IO LexEntry
- NLP.HistPL.Types: Context :: [Repr] -> Context
- NLP.HistPL.Types: Definition :: [Repr] -> Definition
- NLP.HistPL.Types: Lemma :: [Repr] -> Lemma
- NLP.HistPL.Types: LexEntry :: Text -> Maybe Text -> Maybe Text -> [Text] -> Lemma -> [WordForm] -> [Text] -> [SynBehaviour] -> [Sense] -> [RelForm] -> LexEntry
- NLP.HistPL.Types: RelForm :: [Repr] -> Text -> RelForm
- NLP.HistPL.Types: Repr :: Text -> Text -> Maybe Text -> Repr
- NLP.HistPL.Types: Sense :: Maybe Text -> [Text] -> [Definition] -> [Context] -> Sense
- NLP.HistPL.Types: SynBehaviour :: [Repr] -> [Text] -> SynBehaviour
- NLP.HistPL.Types: WordForm :: [Repr] -> WordForm
- NLP.HistPL.Types: class HasRepr t
- NLP.HistPL.Types: components :: LexEntry -> [Text]
- NLP.HistPL.Types: cxts :: Sense -> [Context]
- NLP.HistPL.Types: data LexEntry
- NLP.HistPL.Types: data RelForm
- NLP.HistPL.Types: data Repr
- NLP.HistPL.Types: data Sense
- NLP.HistPL.Types: data SynBehaviour
- NLP.HistPL.Types: defs :: Sense -> [Definition]
- NLP.HistPL.Types: forms :: LexEntry -> [WordForm]
- NLP.HistPL.Types: instance Binary Context
- NLP.HistPL.Types: instance Binary Definition
- NLP.HistPL.Types: instance Binary Lemma
- NLP.HistPL.Types: instance Binary LexEntry
- NLP.HistPL.Types: instance Binary RelForm
- NLP.HistPL.Types: instance Binary Repr
- NLP.HistPL.Types: instance Binary Sense
- NLP.HistPL.Types: instance Binary SynBehaviour
- NLP.HistPL.Types: instance Binary WordForm
- NLP.HistPL.Types: instance Eq Context
- NLP.HistPL.Types: instance Eq Definition
- NLP.HistPL.Types: instance Eq Lemma
- NLP.HistPL.Types: instance Eq LexEntry
- NLP.HistPL.Types: instance Eq RelForm
- NLP.HistPL.Types: instance Eq Repr
- NLP.HistPL.Types: instance Eq Sense
- NLP.HistPL.Types: instance Eq SynBehaviour
- NLP.HistPL.Types: instance Eq WordForm
- NLP.HistPL.Types: instance HasRepr Context
- NLP.HistPL.Types: instance HasRepr Definition
- NLP.HistPL.Types: instance HasRepr Lemma
- NLP.HistPL.Types: instance HasRepr RelForm
- NLP.HistPL.Types: instance HasRepr SynBehaviour
- NLP.HistPL.Types: instance HasRepr WordForm
- NLP.HistPL.Types: instance HasRepr [Repr]
- NLP.HistPL.Types: instance Ord Context
- NLP.HistPL.Types: instance Ord Definition
- NLP.HistPL.Types: instance Ord Lemma
- NLP.HistPL.Types: instance Ord LexEntry
- NLP.HistPL.Types: instance Ord RelForm
- NLP.HistPL.Types: instance Ord Repr
- NLP.HistPL.Types: instance Ord Sense
- NLP.HistPL.Types: instance Ord SynBehaviour
- NLP.HistPL.Types: instance Ord WordForm
- NLP.HistPL.Types: instance Read Context
- NLP.HistPL.Types: instance Read Definition
- NLP.HistPL.Types: instance Read Lemma
- NLP.HistPL.Types: instance Read LexEntry
- NLP.HistPL.Types: instance Read RelForm
- NLP.HistPL.Types: instance Read Repr
- NLP.HistPL.Types: instance Read Sense
- NLP.HistPL.Types: instance Read SynBehaviour
- NLP.HistPL.Types: instance Read WordForm
- NLP.HistPL.Types: instance Show Context
- NLP.HistPL.Types: instance Show Definition
- NLP.HistPL.Types: instance Show Lemma
- NLP.HistPL.Types: instance Show LexEntry
- NLP.HistPL.Types: instance Show RelForm
- NLP.HistPL.Types: instance Show Repr
- NLP.HistPL.Types: instance Show Sense
- NLP.HistPL.Types: instance Show SynBehaviour
- NLP.HistPL.Types: instance Show WordForm
- NLP.HistPL.Types: language :: Repr -> Text
- NLP.HistPL.Types: lemma :: LexEntry -> Lemma
- NLP.HistPL.Types: lexId :: LexEntry -> Text
- NLP.HistPL.Types: lineRef :: LexEntry -> Maybe Text
- NLP.HistPL.Types: newtype Context
- NLP.HistPL.Types: newtype Definition
- NLP.HistPL.Types: newtype Lemma
- NLP.HistPL.Types: newtype WordForm
- NLP.HistPL.Types: pos :: LexEntry -> [Text]
- NLP.HistPL.Types: relRepr :: RelForm -> [Repr]
- NLP.HistPL.Types: relTo :: RelForm -> Text
- NLP.HistPL.Types: related :: LexEntry -> [RelForm]
- NLP.HistPL.Types: repr :: HasRepr t => t -> [Repr]
- NLP.HistPL.Types: senseId :: Sense -> Maybe Text
- NLP.HistPL.Types: senses :: LexEntry -> [Sense]
- NLP.HistPL.Types: sourceID :: Repr -> Maybe Text
- NLP.HistPL.Types: status :: LexEntry -> Maybe Text
- NLP.HistPL.Types: style :: Sense -> [Text]
- NLP.HistPL.Types: synRepr :: SynBehaviour -> [Repr]
- NLP.HistPL.Types: synSenseIds :: SynBehaviour -> [Text]
- NLP.HistPL.Types: syntactic :: LexEntry -> [SynBehaviour]
- NLP.HistPL.Types: text :: HasRepr t => t -> [Text]
- NLP.HistPL.Types: writtenForm :: Repr -> Text
+ NLP.HistPL.Lexicon: build :: FilePath -> [(LexEntry, Set Text)] -> IO (HistPL)
+ NLP.HistPL.Lexicon: dictIDs :: HistPL -> IO [Text]
+ NLP.HistPL.Lexicon: dictKeys :: HistPL -> IO [Key]
+ NLP.HistPL.Lexicon: load' :: HistPL -> Text -> IO LexEntry
+ NLP.HistPL.Lexicon: loadAll :: HistPL -> IO [(Key, LexEntry)]
+ NLP.HistPL.Lexicon: tryLoad :: HistPL -> Key -> IO (Maybe LexEntry)
+ NLP.HistPL.Lexicon: tryLoad' :: HistPL -> Text -> IO (Maybe LexEntry)
- NLP.HistPL.Lexicon: load :: HistPL -> IO [(Key, LexEntry)]
+ NLP.HistPL.Lexicon: load :: HistPL -> Key -> IO LexEntry

Files

hist-pl-lexicon.cabal view
@@ -1,11 +1,9 @@ name:               hist-pl-lexicon-version:            0.4.0+version:            0.5.0 synopsis:           A binary representation of the historical dictionary of Polish description:     The library provides a binary representation of the historical-    dictionary of Polish and language markup format (LMF) parsing-    utilities which allow to translate the original LMF representation-    of the dictionary to the binary form.+    dictionary of Polish. license:            BSD3 license-file:       LICENSE cabal-version:      >= 1.6@@ -19,35 +17,24 @@  library   hs-source-dirs:   src-  exposed-modules:    NLP.HistPL.Types-                    , NLP.HistPL.LMF-                    , NLP.HistPL.LMF.Parse-                    , NLP.HistPL.LMF.Show-                    , NLP.HistPL.Util-                    , NLP.HistPL.Dict+  exposed-modules:    NLP.HistPL.Util                     , NLP.HistPL.Lexicon+  other-modules:      NLP.HistPL.Binary+                    , NLP.HistPL.Binary.Util   build-depends:      base >= 4 && < 5                      , containers+                    , binary+                    , text                     , directory                     , filepath-                    , text-                    , binary-                    , text-binary >= 0.1 && < 0.2-                    , polysoup >= 0.1 && < 0.2-                    , dawg >= 0.9 && < 0.10                     , transformers-                    , mtl+                    , lazy-io >= 0.1 && < 0.2+                    , dawg >= 0.9 && < 0.10+                    , hist-pl-types >= 0.1 && < 0.2+                    , hist-pl-dawg >= 0.1 && < 0.2    ghc-options: -Wall  source-repository head     type: git     location: https://github.com/kawu/hist-pl.git---- executable hist-pl-binarize---   hs-source-dirs: src, tools---   main-is: hist-pl-binarize.hs--- --- executable hist-pl-show---   hs-source-dirs: src, tools---   main-is: hist-pl-show.hs
+ src/NLP/HistPL/Binary.hs view
@@ -0,0 +1,47 @@+module NLP.HistPL.Binary+( save+, load+, tryLoad+, dictIDs+, loadAll+) where+++import           Prelude hiding (lookup)+import           Control.Applicative ((<$>))+import           System.FilePath ((</>))+import           Data.Binary (encodeFile, decodeFile)+import qualified Data.Text as T+import qualified Control.Monad.LazyIO as LazyIO++import           NLP.HistPL.Types+import           NLP.HistPL.Binary.Util+++-- | Save entry in the given directory (the actual entry path+-- is determined on the basis of the `lexID`).+save :: FilePath -> LexEntry -> IO ()+save path x = encodeFile (path </> T.unpack (lexID x)) x+++-- | Lookup entry with a given `lexID`.+load :: FilePath -> T.Text -> IO LexEntry+load path i = tryLoad path i >>=+    maybe (fail "load: failed to load the entry") return+++-- | Lookup entry with a given `lexID`.+tryLoad :: FilePath -> T.Text -> IO (Maybe LexEntry)+tryLoad path i = maybeErr $ decodeFile (path </> T.unpack i)+++-- | Get a list of entry identifiers stored in the dictionary.+dictIDs :: FilePath -> IO [T.Text]+dictIDs path = map T.pack <$> loadContents path+++-- | Load all lexical entries in a lazy manner.+loadAll :: FilePath -> IO [LexEntry]+loadAll path = do+    ids <- dictIDs path+    LazyIO.forM ids $ load path
+ src/NLP/HistPL/Binary/Util.hs view
@@ -0,0 +1,48 @@+{-# LANGUAGE ScopedTypeVariables #-} +++module NLP.HistPL.Binary.Util+( loadContents+, emptyDirectory+, maybeErr+, maybeT+, maybeErrT+) where+++import           Control.Applicative ((<$>))+import           Control.Monad.IO.Class (liftIO, MonadIO)+import           Control.Exception (try, SomeException)+import           Control.Monad.Trans.Maybe (MaybeT (..))+import           System.Directory (getDirectoryContents)+++-- | Load the directory contents.+loadContents :: FilePath -> IO [FilePath]+loadContents path = do+    xs <- getDirectoryContents path+    return [x | x <- xs, x /= ".", x /= ".."]+++-- | Check if the directory is empty.+emptyDirectory :: FilePath -> IO Bool+emptyDirectory path = null <$> loadContents path+++maybeErr :: MonadIO m => IO a -> m (Maybe a)+maybeErr io = do+    r <- liftIO (try io)+    case r of+        Left (_e :: SomeException)  -> return Nothing+        Right x                     -> return (Just x)+++maybeT :: Monad m => Maybe a -> MaybeT m a+maybeT = MaybeT . return+{-# INLINE maybeT #-}+++maybeErrT :: MonadIO m => IO a -> MaybeT m a+maybeErrT io = do+    r <- liftIO (maybeErr io)+    maybeT r
− src/NLP/HistPL/Dict.hs
@@ -1,209 +0,0 @@-{-# LANGUAGE RecordWildCards #-}-{-# LANGUAGE TupleSections #-}----- | A `D.DAWG`-based dictionary.---module NLP.HistPL.Dict-(--- * Rule-  Rule (..)-, apply-, between---- * Dictionary-, Dict--- ** Entry-, Lex (..)-, Key (..)-, Val (..)-, Node--- ** Entry set-, LexSet-, mkLexSet-, unLexSet--- , encode-, decode--- ** Query-, lookup--- ** Conversion-, fromList-, toList-, entries-, revDict-) where---import Prelude hiding (lookup)-import Control.Applicative ((<$>), (<*>))-import Control.Arrow (first)-import Data.Binary (Binary, get, put)-import Data.Text.Binary ()-import qualified Data.Map as M-import qualified Data.Text as T-import qualified Data.DAWG.Static as D------------------------------------------------------------------------------ Rule------------------------------------------------------------------------------ | A rule for translating a form into another form.-data Rule = Rule {-    -- | Number of characters to cut from the end of the form.-      cut       :: !Int-    -- | A suffix to paste.-    , suffix    :: !T.Text-    } deriving (Show, Eq, Ord)---instance Binary Rule where-    put Rule{..} = put cut >> put suffix-    get = Rule <$> get <*> get----- | Apply the rule.-apply :: Rule -> T.Text -> T.Text-apply r x = T.take (T.length x - cut r) x `T.append` suffix r----- | Determine a rule which translates between two strings.-between :: T.Text -> T.Text -> Rule-between source dest =-    let k = lcp source dest-    in  Rule (T.length source - k) (T.drop k dest)-  where-    lcp a b = case T.commonPrefixes a b of-        Just (c, _, _)  -> T.length c-        Nothing         -> 0------------------------------------------------------------------------------ Entry componenets (key and value)------------------------------------------------------------------------------ | A key of a dictionary entry.-data Key i = Key {-    -- | A path of the entry, i.e. DAWG key.-      path  :: T.Text-    -- | Unique identifier among entries with the same `path`.-    , uid   :: i }-    deriving (Show, Eq, Ord)----- | A value of the entry.-data Val a w b = Val {-    -- | Additional information assigned to the entry.-      info  :: a-    -- | A map of forms with additional info of type @b@ assigned.-    -- Invariant: in case of a reverse dictionary (from word forms-    -- to base forms) this map should contain exactly one element-    -- (a base form and a corresonding info).-    , forms :: M.Map w b }-    deriving (Show, Eq, Ord)---instance (Ord w, Binary a, Binary w, Binary b) => Binary (Val a w b) where-    put Val{..} = put info >> put forms-    get = Val <$> get <*> get----- | A dictionary entry consists of a `Key` and a `Val`ue.-data Lex i a b = Lex {-    -- | Entry key.-      lexKey :: Key i-    -- | Entry value.-    , lexVal :: Val a T.Text b }-    deriving (Show, Eq, Ord)----- | A set of dictionary entries.-type LexSet i a b = M.Map (Key i) (Val a T.Text b)----- | Make lexical set from a list of entries.-mkLexSet :: Ord i => [Lex i a b] -> LexSet i a b-mkLexSet = M.fromList . map ((,) <$> lexKey <*> lexVal)----- | List lexical entries.-unLexSet :: LexSet i a b -> [Lex i a b]-unLexSet = map (uncurry Lex) . M.toList----- | Actual values stored in automaton states contain--- all entry information but `path`.-type Node i a b = M.Map i (Val a Rule b)----- | Map function over entry word forms.-mapW :: Ord w' => (w -> w') -> Val a w b -> Val a w' b-mapW f v =-    let g = M.fromList . map (first f) . M.toList-    in  v { forms = g (forms v) }----- | Encode dictionary value given `path`.----- | Decode dictionary value given `path`.-decode :: Ord i => T.Text -> Node i a b -> LexSet i a b-decode x n = M.fromList-    [ (Key x i, mapW (flip apply x) val)-    | (i, val) <- M.toList n ]----- | Transform entry into a list.-toListE :: Lex i a b -> [(T.Text, i, a, T.Text, b)]-toListE (Lex Key{..} Val{..}) =-    [ (path, uid, info, form, y)-    | (form, y) <- M.assocs forms ]-------------------------------------------------------------------------------- | A dictionary parametrized over ID @i@, with info @a@ for every--- (key, i) pair and info @b@ for every (key, i, apply rule key) triple.-type Dict i a b = D.DAWG Char () (Node i a b)----- | Lookup the key in the dictionary.-lookup :: Ord i => T.Text -> Dict i a b -> LexSet i a b-lookup x dict = decode x $ case D.lookup (T.unpack x) dict of-    Just m  -> m-    Nothing -> M.empty----- | List dictionary lexical entries.-entries :: Ord i => Dict i a b -> [Lex i a b]-entries = concatMap f . D.assocs where-    f (key, val) = unLexSet $ decode (T.pack key) val----- | Make dictionary from a list of (key, ID, entry info, form,--- entry\/form info) tuples.-fromList :: (Ord i, Ord a, Ord b) => [(T.Text, i, a, T.Text, b)] -> Dict i a b-fromList xs = D.fromListWith union $-    [ ( T.unpack x-      , M.singleton i (Val a (M.singleton (between x y) b)) )-    | (x, i, a, y, b) <- xs ]-  where-    union = M.unionWith $ both const M.union-    both f g (Val x y) (Val x' y') = Val (f x x') (g y y')----- | Transform dictionary back into the list of (key, ID, key\/ID info, elem,--- key\/ID\/elem info) tuples.-toList :: (Ord i, Ord a, Ord b) => Dict i a b -> [(T.Text, i, a, T.Text, b)]-toList = concatMap toListE . entries----- | Reverse the dictionary.-revDict :: (Ord i, Ord a, Ord b) => Dict i a b -> Dict i a b-revDict = -    let swap (base, i, x, form, y) = (form, i, x, base, y)-    in  fromList . map swap . toList
− src/NLP/HistPL/LMF.hs
@@ -1,9 +0,0 @@--- | Re-export modules from the LMF hierarchy.--module NLP.HistPL.LMF-( module NLP.HistPL.LMF.Parse-, module NLP.HistPL.LMF.Show-) where--import NLP.HistPL.LMF.Parse-import NLP.HistPL.LMF.Show
− src/NLP/HistPL/LMF/Parse.hs
@@ -1,160 +0,0 @@-{-# LANGUAGE OverloadedStrings #-}---- | The module provides parsing utilities for the LMF dictionary.--module NLP.HistPL.LMF.Parse-( readLMF-, parseLMF-, parseLexEntry-) where--import Control.Monad (join)-import Data.Maybe (mapMaybe, listToMaybe)-import qualified Data.Text as T-import qualified Data.Text.Lazy as L-import qualified Data.Text.Lazy.IO as L-import qualified Text.XML.PolySoup as Soup-import Text.XML.PolySoup hiding (XmlParser, Parser, join)--import NLP.HistPL.Types--import Debug.Trace (trace)--type Parser a = Soup.XmlParser L.Text a--lmfP :: Parser [LexEntry]-lmfP = true //> lexEntryP--lexEntryP :: Parser LexEntry-lexEntryP = tag "LexicalEntry" *> getAttr "id" >^>-  \lexId' -> collTags >>=-  \tags   -> return $-    let with p = tagsParseXml (findAll p) tags-    in  LexEntry-        { lexId         = L.toStrict lexId'-        , lineRef       = listToMaybe $ with lineRefP-        , status        = listToMaybe $ with statusP-        , pos           = with posP-        , lemma         = first "lemmaP" (with lemmaP)-        , forms         = with formP-        , components    = join (with compoP)-        , syntactic     = with synP-        , senses        = with senseP-        , related       = with relP }-    -first :: Show a => String -> [a] -> a-first _   [x] = x-first src []  = error $ src ++ ": null xs"-first src xs  = error $ src ++ ": xs == " ++ show xs--posP :: Parser T.Text-posP = featP "partOfSpeech"--lineRefP :: Parser T.Text-lineRefP = featP "lineRef"--statusP :: Parser T.Text-statusP = featP "status"--lemmaP :: Parser Lemma-lemmaP = Lemma <$> (tag "Lemma" /> reprP)--formP :: Parser WordForm-formP = WordForm <$> (tag "WordForm" /> reprP)--compoP :: Parser [T.Text]-compoP = map L.toStrict <$> (tag "ListOfComponents" /> cut (getAttr "entry"))--relP :: Parser RelForm-relP = tag "RelatedForm" *> getAttr "targets" >^> \relTo' -> do-    rs <- many reprP-    return $ RelForm-        { relRepr = rs-        , relTo   = L.toStrict relTo' }--otherP :: Parser ()-otherP = tagOpenName >^> \name ->-    warning ("tag " ++ L.unpack name ++ " ignored") ignore--warning :: String -> Parser a -> Parser a-warning msg x = trace ("WARNING: " ++ msg) x--grave :: String -> Parser a -> Parser a-grave msg x = trace ("ERROR: " ++ msg) x--grave' :: String -> a -> Parser a-grave' msg x = grave msg (return x)--synP :: Parser SynBehaviour-synP = tag "SyntacticBehaviour" *> getAttr "senses" >^> \senses' -> do-    repr' <- reprBodyP-    let senseIds = T.words (L.toStrict senses')-    return (SynBehaviour [repr'] senseIds)--data SenseContent-    = SenseDef Definition-    | SenseStyle T.Text-    | SenseCxt Context-    | SenseOther ()--senseStyle :: SenseContent -> Maybe T.Text-senseStyle (SenseStyle x) = Just x-senseStyle _              = Nothing--senseDef :: SenseContent -> Maybe Definition-senseDef (SenseDef def) = Just def-senseDef _              = Nothing--senseCxt :: SenseContent -> Maybe Context-senseCxt (SenseCxt cxt) = Just cxt-senseCxt _              = Nothing--senseP :: Parser Sense-senseP = tag "Sense" *> maybeAttr "id" >^> \senseId' -> do-    xs <- many $ oneOf-        [ SenseDef      <$> defP-        , SenseStyle    <$> styleP-        , SenseCxt      <$> cxtP-        , SenseOther    <$> otherP ]-    let styl' = mapMaybe senseStyle xs-    let defs' = mapMaybe senseDef xs-    let cxts' = mapMaybe senseCxt xs-    return $ Sense-        { senseId = L.toStrict <$> senseId'-        , style = styl'-        , defs  = defs'-        , cxts  = cxts' }--defP :: Parser Definition-defP = Definition <$> (tag "Definition" /> reprP)--cxtP :: Parser Context-cxtP = Context <$> (tag "Context" /> reprP)--styleP :: Parser T.Text-styleP = featP "style"--reprP :: Parser Repr-reprP = tag "FormRepresentation" <|> tag "TextRepresentation" ^> reprBodyP--reprBodyP :: Parser Repr-reprBodyP = Repr-    <$> featP "writtenForm"-    <*> (featP "language" <|> grave' "language not specified" "polh")-    <*> (optional $ featP "sourceID")--featP :: L.Text -> Parser T.Text-featP att = L.toStrict <$>-    cut (tag "feat" *> hasAttr "att" att *> getAttr "val")---- | Read the dictionary from the LMF file.-readLMF :: FilePath -> IO [LexEntry]-readLMF = fmap parseLMF . L.readFile---- | Parse the entire dictionary in the LMF format.-parseLMF :: L.Text -> [LexEntry]-parseLMF = parseXml lmfP---- | Parse the lexical entry LMF representation-parseLexEntry :: L.Text -> LexEntry-parseLexEntry = parseXml lexEntryP
− src/NLP/HistPL/LMF/Show.hs
@@ -1,170 +0,0 @@-{-# LANGUAGE OverloadedStrings #-}---- | Printing utilities for the LMF dictionary format.--module NLP.HistPL.LMF.Show-( showLMF-, showLexEntry-) where--import Data.Monoid (Monoid, mappend, mconcat)-import Data.List (intersperse)-import Data.Maybe (maybeToList)-import qualified Data.Text as T-import qualified Data.Text.Lazy as L-import qualified Data.Text.Lazy.Builder as L-import Text.XML.PolySoup (escapeXml)--import NLP.HistPL.Types---- | An infix synonym for 'mappend'.-{-# INLINE (<>) #-}-(<>) :: Monoid m => m -> m -> m-(<>) = mappend---- | Indentation parameter.-indentSize :: Int-indentSize = 2--identPref :: L.Builder-identPref = L.fromLazyText (L.replicate (fromIntegral indentSize) " ")--{-# INLINE ident #-}-ident :: L.Builder -> L.Builder-ident = (identPref <>)--prolog :: [L.Builder]-prolog =-    [ "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"-    , "<LexicalResource dtdVersion=\"16\">"-    , "  <GlobalInformation>"-    , "    <feat att=\"languageCoding\" val=\"ISO 639-6\"/>"-    , "  </GlobalInformation>"-    , "  <Lexicon>" ]--epilog :: [L.Builder]-epilog =-    [ "  </Lexicon>"-    , "</LexicalResource>" ]---- | Show the entire dictionary as a lazy text in the LMF format.-showLMF :: [LexEntry] -> L.Text-showLMF =-    L.toLazyText . mconcat . map (<> "\n") . embed . concatMap buildLexEntry-    where embed body = prolog ++ map (ident.ident) body ++ epilog---- | Show lexical entry using the LMF format.-showLexEntry :: LexEntry -> L.Text-showLexEntry =-    L.toLazyText . mconcat . map (<> "\n") . buildLexEntry--buildElem :: L.Builder -> [L.Builder] -> L.Builder -> [L.Builder]-buildElem beg body end = beg : map ident body ++ [end] ---- | Each output line is represented as a builder. We use separate builders--- for separate lines because we want to easilly indent the output text.-buildLexEntry :: LexEntry -> [L.Builder]-buildLexEntry lx =-    buildElem beg body end-  where-    beg = "<LexicalEntry id=\"" <> L.fromText (lexId lx) <> "\">"-    end = "</LexicalEntry>"-    body-        =  map (buildFeat "lineRef") (maybeToList $ lineRef lx)-        ++ map (buildFeat "status") (maybeToList $ status lx)-        ++ map (buildFeat "partOfSpeech") (pos lx)-        ++ buildLemma (lemma lx)-        ++ concatMap buildForm (forms lx)-        ++ concatMap buildRelForm (related lx)-        ++ buildComps (components lx)-        ++ concatMap buildSyn (syntactic lx)-        ++ concatMap buildSense (senses lx)--buildLemma :: Lemma -> [L.Builder]-buildLemma base =-    buildElem beg body end-  where-    beg = "<Lemma>"-    end = "</Lemma>"-    body = concatMap (buildRepr "FormRepresentation") (repr base)--buildForm :: WordForm -> [L.Builder]-buildForm form =-    buildElem beg body end-  where-    beg = "<WordForm>"-    end = "</WordForm>"-    body = concatMap (buildRepr "FormRepresentation") (repr form)--buildRelForm :: RelForm -> [L.Builder]-buildRelForm form =-    buildElem beg body end-  where-    beg = "<RelatedForm targets=\"" <> L.fromText (relTo form) <> "\">"-    end = "</RelatedForm>"-    body = concatMap (buildRepr "FormRepresentation") (repr form)--buildComps :: [T.Text] -> [L.Builder]-buildComps [] = []-buildComps xs =-    buildElem beg body end-  where-    beg = "<ListOfComponents>"-    end = "</ListOfComponents>"-    body = map comp xs-    comp x = "<Component entry=\"" <> L.fromText x <> "\"/>"--buildSyn :: SynBehaviour -> [L.Builder]-buildSyn syn =-    buildElem beg body end-  where-    ids = mconcat . intersperse " " . map L.fromText $ synSenseIds syn-    beg = "<SyntacticBehaviour senses=\"" <> ids <> "\">"-    end = "</SyntacticBehaviour>"-    body = concatMap (buildRepr "TextRepresentation") (repr syn)--buildSense :: Sense -> [L.Builder]-buildSense sense =-    buildElem beg body end-  where-    beg = case senseId sense of-        Just x  -> "<Sense id=\"" <> L.fromText x <> "\">"-        Nothing -> "<Sense>"-    end = "</Sense>"-    body-        =  map (buildFeat "style") (style sense)-        ++ concatMap buildDef (defs sense)-        ++ concatMap buildCxt (cxts sense)--buildDef :: Definition -> [L.Builder]-buildDef def =-    buildElem beg body end-  where-    beg = "<Definition>"-    end = "</Definition>"-    body = concatMap (buildRepr "TextRepresentation") (repr def)--buildCxt :: Context -> [L.Builder]-buildCxt cxt =-    buildElem beg body end-  where-    beg = "<Context>"-    end = "</Context>"-    body = concatMap (buildRepr "TextRepresentation") (repr cxt)--buildRepr :: L.Builder -> Repr -> [L.Builder]-buildRepr tag rp =-    buildElem beg body end-  where-    beg = "<"  <> tag <> ">"-    end = "</" <> tag <> ">"-    body =-        [ buildFeat "writtenForm" . escapeXml $ writtenForm rp-        , buildFeat "language" (language rp) ] ++ source-    source = case sourceID rp of-        Just x  -> [buildFeat "sourceID" x]-        Nothing -> []--buildFeat :: L.Builder -> T.Text -> L.Builder-buildFeat att val =-    "<feat att=\"" <> att <> "\" val=\"" <> L.fromText val <> "\"/>"
src/NLP/HistPL/Lexicon.hs view
@@ -1,7 +1,5 @@-{-# LANGUAGE GeneralizedNewtypeDeriving #-} -{-# LANGUAGE ScopedTypeVariables #-} -{-# LANGUAGE RecordWildCards #-}  {-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE RecordWildCards #-}  {-# LANGUAGE TupleSections #-}   @@ -14,10 +12,8 @@      > import qualified NLP.HistPL.Lexicon as H    -    Use `save` and `load` functions to save/load-    the entire dictionary in/from a given directory.  They are-    particularly useful when you want to convert the @LMF@ dictionary-    to a binary format (see "NLP.HistPL.LMF" module).+    Use `build` and `loadAll` functions to save/load+    the entire dictionary in/from a given directory.         To search the dictionary, open the binary directory with an     `open` function.  For example, during a @GHCi@ session:@@ -37,6 +33,10 @@      >>> map (H.text . H.lemma) entries     [["dufliwy"]]++    Finally, if you need to follow an ID pointer kept in one entry+    as a reference to another one, use the `load'` or `tryLoad'`+    functions. -}  @@ -51,18 +51,23 @@ -- ** Open , tryOpen , open--- ** Query++-- * Query+-- ** By Form , lookup , lookupMany-, getIndex-, tryWithKey-, withKey+-- ** By Key+, dictKeys+, tryLoad+, load+-- ** By ID+, dictIDs+, tryLoad'+, load'  -- * Conversion--- ** Save-, save--- ** Load-, load+, build+, loadAll  -- * Modules -- $modules@@ -71,23 +76,26 @@   import Prelude hiding (lookup)-import Control.Exception (try, SomeException)-import Control.Applicative (Applicative, (<$>), (<*>))-import Control.Monad (when, guard)+import Control.Applicative ((<$>))+import Control.Monad (unless, guard) import Control.Monad.IO.Class (liftIO, MonadIO) import Control.Monad.Trans.Maybe (MaybeT (..))+import qualified Control.Monad.LazyIO as LazyIO import System.IO.Unsafe (unsafeInterleaveIO) import System.FilePath ((</>))-import System.Directory ( getDirectoryContents, createDirectoryIfMissing-                        , createDirectory, doesDirectoryExist )+import System.Directory+    ( createDirectoryIfMissing, createDirectory, doesDirectoryExist ) import Data.List (mapAccumL) import Data.Binary (Binary, put, get, encodeFile, decodeFile) import qualified Data.Set as S import qualified Data.Map as M import qualified Data.Text as T+import qualified Data.Text.IO as T import qualified Data.DAWG.Dynamic as DD -import qualified NLP.HistPL.Dict as D+import qualified NLP.HistPL.Binary as B+import           NLP.HistPL.Binary.Util+import qualified NLP.HistPL.DAWG as D import           NLP.HistPL.Types import qualified NLP.HistPL.Util as Util @@ -98,16 +106,31 @@ -}  +--------------------------------------------------------+-- Subdirectories+--------------------------------------------------------++ -- | Path to entries in the binary dictionary. entryDir :: String entryDir = "entries"  +-- | Path to keys in the binary dictionary.+keyDir :: String+keyDir = "keys"++ -- | Path to key map in the binary dictionary.-formMapFile :: String-formMapFile = "forms.bin"+formFile :: String+formFile = "forms.bin"  +--------------------------------------------------------+-- Key+--------------------------------------------------------++ -- | A dictionary key which uniquely identifies the lexical entry. type Key = D.Key UID @@ -116,7 +139,7 @@ type UID = Int  --- | Form representing the lexical entry.+-- | The ''main form'' of the lexical entry. proxy :: LexEntry -> T.Text proxy entry = case Util.allForms entry of     (x:_)   -> x@@ -136,21 +159,9 @@     in  D.Key (T.pack form'S) (read uid'S)  --- | Load the directory contents.-loadContents :: FilePath -> IO [FilePath]-loadContents path = do-    xs <- getDirectoryContents path-    return [x | x <- xs, x /= ".", x /= ".."]----- | Check if the directory is empty.-emptyDirectory :: FilePath -> IO Bool-emptyDirectory path = null <$> loadContents path----- | Save entry on a disk under the given key.-saveEntry :: FilePath -> Key -> LexEntry -> IO ()-saveEntry path x y = encodeFile (path </> showKey x) y+--------------------------------------------------------+-- Computing keys+--------------------------------------------------------   getKey :: DD.DAWG Char Int -> LexEntry -> (DD.DAWG Char Int, Key)@@ -166,42 +177,47 @@ getKeys = snd . mapAccumL getKey DD.empty  -mapIO'Lazy :: (a -> IO b) -> [a] -> IO [b]-mapIO'Lazy f (x:xs) = (:) <$> f x <*> unsafeInterleaveIO (mapIO'Lazy f xs)-mapIO'Lazy _ []     = return []+--------------------------------------------------------+-- Keys storage+--------------------------------------------------------  -forIO'Lazy :: [a] -> (a -> IO b) -> IO [b]-forIO'Lazy = flip mapIO'Lazy+-- | Save (key, lexID) pair in the keys component of the binary dictionary.+saveKey :: FilePath -> Key -> T.Text -> IO ()+saveKey path key i = T.writeFile (path </> keyDir </> showKey key) i  -maybeErr :: MonadIO m => IO a -> m (Maybe a)-maybeErr io = do-    r <- liftIO (try io)-    case r of-        Left (_e :: SomeException)  -> return Nothing-        Right x                     -> return (Just x)+-- | Load lexID given the corresponding key.+loadKey :: FilePath -> Key -> IO T.Text+loadKey path key = T.readFile (path </> keyDir </> showKey key)  -maybeT :: Monad m => Maybe a -> MaybeT m a-maybeT = MaybeT . return-{-# INLINE maybeT #-}+--------------------------------------------------------+-- Entry storage+--------------------------------------------------------  -maybeErrT :: MonadIO m => IO a -> MaybeT m a-maybeErrT io = do-    r <- liftIO (maybeErr io)-    maybeT r+-- | Save entry in the binary dictionary.+saveEntry :: FilePath -> Key -> LexEntry -> IO ()+saveEntry path key x = do+    saveKey path key (lexID x)+    B.save (path </> entryDir) x  --- | Load lexical entry from disk by its key.-loadEntry :: FilePath -> Key -> IO (Maybe LexEntry)-loadEntry path key = do-    maybeErr $ decodeFile (path </> showKey key)+-- -- | Load entry from a disk by its key.+-- loadEntry :: FilePath -> Key -> IO LexEntry+-- loadEntry path key = tryLoadEntry path key >>=+--     maybe (fail "load: failed to load the entry") return  +-- | Load entry from a disk by its key.+tryLoadEntry :: FilePath -> Key -> IO (Maybe LexEntry)+tryLoadEntry path key = maybeErr $ do+    B.load (path </> entryDir) =<< loadKey path key++ ----------------------------------------------------------- Binary interface+-- Binary dictionary --------------------------------------------------------  @@ -212,7 +228,7 @@     -- | A path to the binary dictionary.       dictPath  :: FilePath     -- | A dictionary with lexicon forms.-    , formMap   :: D.Dict UID () Code+    , formMap   :: D.DAWG UID () Code     }  @@ -235,17 +251,12 @@         c   -> error $ "get: invalid Code value '" ++ [c] ++ "'"  --- | Path to directory with entries.-entryPath :: HistPL -> FilePath-entryPath = (</> entryDir) . dictPath-- -- | Open the binary dictionary residing in the given directory. -- Return Nothing if the directory doesn't exist or if it doesn't -- constitute a dictionary. tryOpen :: FilePath -> IO (Maybe HistPL) tryOpen path = runMaybeT $ do-    formMap'  <- maybeErrT $ decodeFile (path </> formMapFile)+    formMap'  <- maybeErrT $ decodeFile (path </> formFile)     doesExist <- liftIO $ doesDirectoryExist (path </> entryDir)     guard doesExist      return $ HistPL path formMap'@@ -260,29 +271,49 @@   -- | List of dictionary keys.-getIndex :: HistPL -> IO [Key]-getIndex hpl = map parseKey <$> loadContents (entryPath hpl)+dictKeys :: HistPL -> IO [Key]+dictKeys hpl = map parseKey <$> loadContents (dictPath hpl </> keyDir)  --- | Extract lexical entry with a given key.  Return `Nothing` if there+-- | Load lexical entry given its key.  Return `Nothing` if there -- is no entry with such a key.-tryWithKey :: HistPL -> Key -> IO (Maybe LexEntry)-tryWithKey hpl key = unsafeInterleaveIO $ loadEntry (entryPath hpl) key+tryLoad :: HistPL -> Key -> IO (Maybe LexEntry)+tryLoad hpl key = unsafeInterleaveIO $ tryLoadEntry (dictPath hpl) key  --- | Extract lexical entry with a given key.  Raise error if there+-- | Load lexical entry given its key.  Raise error if there -- is no entry with such a key.-withKey :: HistPL -> Key -> IO LexEntry-withKey hpl key = tryWithKey hpl key >>= maybe-    (fail $ "Failed to open entry with the " ++ show key ++ " key") return+load :: HistPL -> Key -> IO LexEntry+load hpl key = tryLoad hpl key >>= maybe+    (fail $ "load: failed to open entry with the " ++ show key ++ " key")+    return  +-- | List of dictionary IDs.+dictIDs :: HistPL -> IO [T.Text]+dictIDs hpl = map T.pack <$> loadContents (dictPath hpl </> entryDir)+++-- | Load lexical entry given its ID.  Return `Nothing` if there+-- is no entry with such ID.+tryLoad' :: HistPL -> T.Text -> IO (Maybe LexEntry)+tryLoad' hpl i = unsafeInterleaveIO $ B.tryLoad (dictPath hpl </> entryDir) i+++-- | Load lexical entry given its ID.  Raise error if there+-- is no entry with such a key.+load' :: HistPL -> T.Text -> IO LexEntry+load' hpl i = tryLoad' hpl i >>= maybe+    (fail $ "load': failed to load entry with the " ++ T.unpack i ++ " ID")+    return++ -- | Lookup the form in the dictionary. lookup :: HistPL -> T.Text -> IO [(LexEntry, Code)] lookup hpl x = do     let lexSet = D.lookup x (formMap hpl)     sequence-        [ (   , code) <$> withKey hpl key+        [ (   , code) <$> load hpl key         | (key, code) <- getCode =<< M.assocs lexSet ]   where     getCode (key, val) =@@ -297,7 +328,7 @@             getCode =<< M.assocs =<<             (flip D.lookup (formMap hpl) <$> xs)     sequence-        [ (   , code) <$> withKey hpl key+        [ (   , code) <$> load hpl key         | (key, code) <- M.toList keyMap ]   where     getCode (key, val) =@@ -313,23 +344,22 @@ -- | Construct dictionary from a list of lexical entries and save it in -- the given directory.  To each entry an additional set of forms can -- be assigned.  -save :: FilePath -> [(LexEntry, S.Set T.Text)] -> IO (HistPL)-save binPath xs = do+build :: FilePath -> [(LexEntry, S.Set T.Text)] -> IO (HistPL)+build binPath xs = do     createDirectoryIfMissing True binPath-    isEmpty <- emptyDirectory binPath-    when (not isEmpty) $ do-        error $ "save: directory " ++ binPath ++ " is not empty"-    let lexPath = binPath </> entryDir-    createDirectory lexPath+    emptyDirectory binPath >>= \empty -> unless empty $ do+        error $ "build: directory " ++ binPath ++ " is not empty"+    createDirectory $ binPath </> entryDir+    createDirectory $ binPath </> keyDir     formMap' <- D.fromList . concat <$>-        mapIO'Lazy (saveBin lexPath) (zip3 keys entries forms)-    encodeFile (binPath </> formMapFile) formMap'+        LazyIO.mapM saveBin (zip3 keys entries forms)+    encodeFile (binPath </> formFile) formMap'     return $ HistPL binPath formMap'   where     (entries, forms) = unzip xs     keys = getKeys entries-    saveBin lexPath (key, lexEntry, otherForms) = do-        saveEntry lexPath key lexEntry+    saveBin (key, lexEntry, otherForms) = do+        saveEntry binPath key lexEntry         let D.Key{..} = key             histForms = S.fromList (Util.allForms lexEntry)             onlyHist  = S.difference histForms otherForms@@ -340,9 +370,9 @@   -- | Load all lexical entries in a lazy manner.-load :: HistPL -> IO [(Key, LexEntry)]-load hpl = do-    keys <- getIndex hpl-    forIO'Lazy keys $ \key -> do-        entry <- withKey hpl key+loadAll :: HistPL -> IO [(Key, LexEntry)]+loadAll hpl = do+    keys <- dictKeys hpl+    LazyIO.forM keys $ \key -> do+        entry <- load hpl key         return (key, entry)
− src/NLP/HistPL/Types.hs
@@ -1,155 +0,0 @@-{-# LANGUAGE RecordWildCards #-}-{-# LANGUAGE GeneralizedNewtypeDeriving #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE TypeSynonymInstances #-}---- | A data type hierarchy provided by this module mirrors--- the hierarchy of structures kept in the original, LMF--- representation of the historical dictionary of Polish.--module NLP.HistPL.Types-( Repr (..)-, HasRepr (..)-, text-, WordForm (..)-, Lemma (..)-, RelForm (..)-, Definition (..)-, Context (..)-, SynBehaviour (..)-, Sense (..)-, LexEntry (..)-) where--import Control.Applicative ((<$>), (<*>))-import qualified Data.Text as T-import Data.Text.Binary ()-import Data.Binary (Binary, put, get)---- | Form or text representation.-data Repr = Repr-    { writtenForm :: T.Text-    , language    :: T.Text-    , sourceID    :: Maybe T.Text }-    deriving (Show, Read, Eq, Ord)--instance Binary Repr where-    put Repr{..} = do-        put writtenForm-        put language-        put sourceID-    get = Repr <$> get <*> get <*> get---- | A class of objects with a written representation.-class HasRepr t where-    repr :: t -> [Repr]--instance HasRepr [Repr] where-    repr = id---- | Get textual representations of an object.-text :: HasRepr t => t -> [T.Text]-text = map writtenForm . repr-{-# INLINE text #-}---- | A word form.-newtype WordForm = WordForm [Repr]-    deriving (Show, Read, Eq, Ord, Binary, HasRepr)---- | A related form.-data RelForm = RelForm-    { relRepr   :: [Repr]-    , relTo     :: T.Text }-    deriving (Show, Read, Eq, Ord)--instance Binary RelForm where-    put RelForm{..} = do-        put relRepr-        put relTo-    get = RelForm <$> get <*> get--instance HasRepr RelForm where-    repr = relRepr---- | A lemma (base) form.-newtype Lemma = Lemma [Repr]-    deriving (Show, Read, Eq, Ord, Binary, HasRepr)---- | A definition of the lexeme sense.-newtype Definition = Definition [Repr]-    deriving (Show, Read, Eq, Ord, Binary, HasRepr)---- | A context in which a given sense is illustrated.-newtype Context = Context [Repr]-    deriving (Show, Read, Eq, Ord, Binary, HasRepr)---- | A description of a syntactic behaviour.-data SynBehaviour = SynBehaviour-    { synRepr     :: [Repr]-    , synSenseIds :: [T.Text] }-    deriving (Show, Read, Eq, Ord)--instance HasRepr SynBehaviour where-    repr = synRepr--instance Binary SynBehaviour where-    put SynBehaviour{..} = do-        put synRepr-        put synSenseIds-    get = SynBehaviour <$> get <*> get---- | A potential sense of a given lexeme.-data Sense = Sense-    { senseId   :: Maybe T.Text-    , style     :: [T.Text]-    , defs      :: [Definition]-    , cxts      :: [Context] }-    deriving (Show, Read, Eq, Ord)--instance Binary Sense where-    put Sense{..} = do-        put senseId-        put style-        put defs-        put cxts-    get = Sense <$> get <*> get <*> get <*> get---- | A description of a lexeme.-data LexEntry = LexEntry {-    -- | An ID of the lexical entry.-      lexId         :: T.Text-    -- | A line reference number.  Provisional field.-    , lineRef       :: Maybe T.Text-    -- | A status of the lexeme.  Provisional field.-    , status        :: Maybe T.Text-    -- | Potential parts of speech.-    , pos           :: [T.Text]-    -- | A base form.-    , lemma         :: Lemma-    -- | Word forms of the lexeme.-    , forms         :: [WordForm]-    -- | A list of components (only when the entry represent-    -- a compound lexeme).-    , components    :: [T.Text]-    -- | A list of potential syntactic behaviours of the lexeme.-    , syntactic     :: [SynBehaviour]-    -- | A list of potential semantic descriptions.-    , senses        :: [Sense]-    -- | Forma related to the lexeme.-    , related       :: [RelForm] }-    deriving (Show, Read, Eq, Ord)--instance Binary LexEntry where-    put LexEntry{..} = do-        put lexId-        put lineRef-        put status-        put pos-        put lemma-        put forms-        put components-        put syntactic-        put senses-        put related-    get = LexEntry <$> get <*> get <*> get <*> get <*> get-                   <*> get <*> get <*> get <*> get <*> get