<commit_before>{-# LANGUAGE RankNTypes, TypeFamilies, FlexibleInstances, MultiParamTypeClasses, UndecidableInstances, BangPatterns #-}
-- | Duck utility functions

module Util
  ( flp
  -- * IO
  , exit
  , dieWith
  , die
  , fputs
  , puts
  , debug
  , debugVal
  -- * List
  , duplicates
  , merge
  , groupPairs
  , spanJust
  , zipCheck
  , zipWithCheck
  , sameLength
  -- * Map
  , insertList
  -- * Functionals
  , uncurry3
  , first, second
  , left, right
  -- * Data
  -- ** Enum
  , allOf
  , TextEnum(..)
  -- ** Stack
  , Stack(..)
  , (++.)
  , splitStack
  -- * Monad
  , nop
  , (>.), (>.=), (>=.)
  , (<<), (.<), (=.<), (.=<)
  , foldM1
  , allM
  , firstM
  , secondM
  , zipWith3M
  -- ** Maybe
  , MaybeT(..)
  , success
  , returnIf
  , mapMaybeT
  -- ** Error and Exception
  , tryError
  , MonadInterrupt(..)
  -- ** Strict Identity
  , Sequence, runSequence
  ) where

import System.IO
import System.Exit
import System.IO.Unsafe
import Data.Function
import Data.List
import Data.Maybe
import Data.Char
import Data.Map (Map)
import qualified Data.Map as Map
import Control.Exception
import Control.Monad.Error
import Control.Monad.State
import Control.Monad.Reader
import Control.Monad.Trans
import Foreign.C.String

flp :: (a,b) -> (b,a)
flp (a,b) = (b,a)

-- |Write a string to a stream all at once.
--
-- The string is written out all at once (as if with fputs in C), so it
-- won't end up interleaved with other strings like 'putStrLn' does.
fputs :: Handle -> String -> IO ()
fputs h s = withCStringLen s (uncurry $ hPutBuf h)

-- |Write a string to stdout with a trailing newline.
puts :: String -> IO ()
puts s = fputs stdout (s++"\n")

debug :: Show a => a -> b -> b
debug a b = unsafePerformIO (puts (show a)) `seq` b

debugVal :: Show a => a -> a
debugVal a = debug a a

-- |Find all entries that occur more than once
duplicates :: Eq a => [a] -> [a]
duplicates l = l \\ nub l

-- |Merge two unique sorted lists, eliminating duplicates.
--
-- Odd behavior will result if the lists are unsorted or contain duplicates.
-- Sorted means sorted in ascending order.
merge :: Ord a => [a] -> [a] -> [a]
merge xs [] = xs
merge [] ys = ys
merge (x:xs) (y:ys) = case compare x y of
  LT -> x : merge xs (y:ys)
  EQ -> x : merge xs ys -- left bias
  GT -> y : merge (x:xs) ys

-- Note: it'd be nice if this was linear time, or at least O(n log n)<commit_msg>switch debug to use Debug.Trace instead of unsafe<commit_after>{-# LANGUAGE RankNTypes, TypeFamilies, FlexibleInstances, MultiParamTypeClasses, UndecidableInstances, BangPatterns #-}
-- | Duck utility functions

module Util
  ( flp
  -- * IO
  , exit
  , dieWith
  , die
  , fputs
  , puts
  , debug
  , debugVal
  -- * List
  , duplicates
  , merge
  , groupPairs
  , spanJust
  , zipCheck
  , zipWithCheck
  , sameLength
  -- * Map
  , insertList
  -- * Functionals
  , uncurry3
  , first, second
  , left, right
  -- * Data
  -- ** Enum
  , allOf
  , TextEnum(..)
  -- ** Stack
  , Stack(..)
  , (++.)
  , splitStack
  -- * Monad
  , nop
  , (>.), (>.=), (>=.)
  , (<<), (.<), (=.<), (.=<)
  , foldM1
  , allM
  , firstM
  , secondM
  , zipWith3M
  -- ** Maybe
  , MaybeT(..)
  , success
  , returnIf
  , mapMaybeT
  -- ** Error and Exception
  , tryError
  , MonadInterrupt(..)
  -- ** Strict Identity
  , Sequence, runSequence
  ) where

import System.IO
import System.Exit
import Data.Function
import Data.List
import Data.Maybe
import Data.Char
import Data.Map (Map)
import qualified Data.Map as Map
import Control.Exception
import Control.Monad.Error
import Control.Monad.State
import Control.Monad.Reader
import Control.Monad.Trans
import Debug.Trace
import Foreign.C.String

flp :: (a,b) -> (b,a)
flp (a,b) = (b,a)

-- |Write a string to a stream all at once.
--
-- The string is written out all at once (as if with fputs in C), so it
-- won't end up interleaved with other strings like 'putStrLn' does.
fputs :: Handle -> String -> IO ()
fputs h s = withCStringLen s (uncurry $ hPutBuf h)

-- |Write a string to stdout with a trailing newline.
puts :: String -> IO ()
puts s = fputs stdout (s++"\n")

debug :: Show a => a -> b -> b
debug = traceShow

debugVal :: Show a => a -> a
debugVal a = debug a a

-- |Find all entries that occur more than once
duplicates :: Eq a => [a] -> [a]
duplicates l = l \\ nub l

-- |Merge two unique sorted lists, eliminating duplicates.
--
-- Odd behavior will result if the lists are unsorted or contain duplicates.
-- Sorted means sorted in ascending order.
merge :: Ord a => [a] -> [a] -> [a]
merge xs [] = xs
merge [] ys = ys
merge (x:xs) (y:ys) = case compare x y of
  LT -> x : merge xs (y:ys)
  EQ -> x : merge xs ys -- left bias
  GT -> y : merge (x:xs) ys

-- Note: it'd be nice if this was linear time, or at least O(n log n)
{'fraction_non_alphanumeric': 0.14366729678638943, 'fraction_numerical': 0.001260239445494644, 'mean_word_length': 2.7000777000777, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 43, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7166608', 'n_tokens_mistral': 1756, 'n_tokens_neox': 1702, 'n_words': 581}