packages feed

streamly-examples-0.1.0: examples/CamelCase.hs

-- ghc -O2  -fspec-constr-recursive=10 -fmax-worker-args=16
-- Convert the input file to camel case and write to stdout

import Data.Function ((&))
import Data.Word (Word8)
import System.Environment (getArgs)
import System.IO (Handle, IOMode(..), openFile, stdout)

import qualified Streamly.Prelude as Stream
import qualified Streamly.FileSystem.Handle as Handle

-- | @camelCase source-file dest-file@
camelCase :: Handle -> Handle -> IO ()
camelCase src dst =
      Stream.unfold Handle.read src      -- SerialT IO Word8
    & Stream.scanl' step (True, Nothing) -- SerialT IO (Bool, Maybe Word8)
    & Stream.mapMaybe snd                -- SerialT IO Word8
    & Stream.fold (Handle.write dst)     -- IO ()

    where

    isNewline x = x == 0x0a
    isUpper x = x >= 0x41 && x <= 0x5a
    isLower x = x >= 0x61 && x <= 0x7a

    -- Scan accumulator @(wasSpace, output)@ contains whether the previous
    -- character was white space, and if the current char should be emitted in
    -- the output.
    step :: (Bool, Maybe Word8) -> Word8 -> (Bool, Maybe Word8)
    step (wasSpace, _) x
        -- Newline or upper case chars go unmodified
        | isNewline x || isUpper x = (False, Just x)
        -- Convert lower to upper if preceded by whitespace
        | isLower x = (False, Just $ if wasSpace then x - 32 else x)
        | otherwise = (True, Nothing)

main :: IO ()
main = do
    name <- fmap head getArgs
    src <- openFile name ReadMode
    camelCase src stdout