packages feed

bitspeak-0.0.1: src/Main.hs

import Data.IORef
import Data.List
import Data.Char
import Control.Monad
import Gui (doGui)
import Corpora (englishCorpus,portugueseCorpus)

alphabet = "abcdefghijklmnopqrstuvwxyz+-,."

{-

    'splitData' is the selection engine. Given a corpus with
    Integer word frequencies a character string is splited
    at a point where a balance of frequency between parts is
    attempted. 'n' parameter is a balance measure.

-}

splitData :: [(String,Integer)] -> Integer -> String -> (String,String)
splitData _ _ [] = ([],[])
splitData sufixes n chars@(ch:ct)
    | n < 0 = reversePair $ splitData sufixes (negate n) (reverse chars)
    | otherwise = (ch:s1,s2)
        where
            reversePair (a,b) = (reverse b,reverse a)
            sh :: [(String,Integer)]
            (sh,st) = (flip partition) sufixes $ (== ch) . head . fst
            np = foldl (+) 1 $ map snd sh
            (s1,s2) = splitData st (n - np) ct

main = do

    -- Following IORefs are all the application state.

    currentWord <- newIORef ""
    fullText <- newIORef [] :: IO (IORef [String])
    choices <- newIORef undefined :: IO (IORef (String,String))
    sufixes <- newIORef undefined :: IO (IORef [(String,Integer)])
    corpus <- newIORef [] :: IO (IORef [(String,Integer)])

    resetSufixes <- return $ readIORef currentWord >>= \w -> readIORef corpus >>=
        \e -> writeIORef sufixes $ filter (not . null . fst) $
        map (uncurry $ (,). (drop (length w))) $ filter (isPrefixOf w . fst) e

    resetChoices <- return $ readIORef sufixes >>= \s ->
        writeIORef choices $ splitData s 0 alphabet

    addToWord <- return $ \c -> modifyIORef currentWord (++ [c])

    enterWord <- return $ readIORef currentWord >>= \w -> when (not $ null w) $
        modifyIORef fullText (++ [w]) >> writeIORef currentWord ""

    undoWord <- return $ do
        w <- readIORef currentWord
        when (null w) $ modifyIORef fullText $ reverse . drop 1 . reverse
        writeIORef currentWord ""

    -- After initialization, doGui is called, provided with
    -- IO functions allowing user actions to be mapped to
    -- actions defined above.

    resetSufixes >> resetChoices

    doGui (readIORef choices) (readIORef currentWord)
        (liftM unwords $ readIORef fullText)
        (writeIORef corpus) $ \leftOrRight -> do
            let side = either (const fst) (const snd) leftOrRight
            sf <- readIORef sufixes
            modifyIORef choices $ splitData sf 0 . side
            readIORef choices >>= \ch -> case ch of
                (c:[],[]) -> do
                    unless (c == '+' || c == '-') $
                        addToWord c
                    when (c == '.') $
                        addToWord '\n'
                    when (c == '+' || c == ',' || c == '.') $
                        enterWord
                    when (c == '-') $
                        undoWord 
                    resetSufixes >> resetChoices
                _ -> return ()