{- |
Module      : Language.Scheme.Util
Copyright   : Justin Ethier
Licence     : MIT (see LICENSE in the distribution)

Maintainer  : github.com/justinethier
Stability   : experimental
Portability : portable

This module contains general-purpose utility functions
-}

module Language.Scheme.Util
    ( countAllLetters
    , countLetters
    , escapeBackslashes
    , lastN'
    , strip
    ) where

import qualified Data.List as DL

-- |A utility function to escape backslashes in the given string
escapeBackslashes :: String -> String
escapeBackslashes :: String -> String
escapeBackslashes = (Char -> String -> String) -> String -> String -> String
forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr Char -> String -> String
step []
  where step :: Char -> String -> String
step Char
x String
xs  | Char
x Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
'\\'  = Char
'\\' Char -> String -> String
forall a. a -> [a] -> [a]
: Char
'\\' Char -> String -> String
forall a. a -> [a] -> [a]
: String
xs
                   | Bool
otherwise =  Char
x Char -> String -> String
forall a. a -> [a] -> [a]
: String
xs 

-- | Remove leading/trailing white space from a string; based on corresponding 
--   Python function. Code taken from: 
--
--   <http://gimbo.org.uk/blog/2007/04/20/splitting-a-string-in-haskell/>
strip :: String -> String
strip :: String -> String
strip String
s = (Char -> Bool) -> String -> String
forall a. (a -> Bool) -> [a] -> [a]
dropWhile Char -> Bool
ws (String -> String) -> String -> String
forall a b. (a -> b) -> a -> b
$ String -> String
forall a. [a] -> [a]
reverse (String -> String) -> String -> String
forall a b. (a -> b) -> a -> b
$ (Char -> Bool) -> String -> String
forall a. (a -> Bool) -> [a] -> [a]
dropWhile Char -> Bool
ws (String -> String) -> String -> String
forall a b. (a -> b) -> a -> b
$ String -> String
forall a. [a] -> [a]
reverse String
s
    where ws :: Char -> Bool
ws = (Char -> String -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Char
' ', Char
'\n', Char
'\t', Char
'\r'])

-- |Count occurences of a letter in a list of strings
countAllLetters :: Char -> [String] -> Int
countAllLetters :: Char -> [String] -> Int
countAllLetters Char
c [String]
strs = [Int] -> Int
forall (t :: * -> *) a. (Foldable t, Num a) => t a -> a
sum ([Int] -> Int) -> [Int] -> Int
forall a b. (a -> b) -> a -> b
$ (String -> Int) -> [String] -> [Int]
forall a b. (a -> b) -> [a] -> [b]
map (Char -> String -> Int
countLetters Char
c) [String]
strs

-- |Count occurences of a letter in a string
countLetters :: Char -> String -> Int
countLetters :: Char -> String -> Int
countLetters Char
c String
str = String -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length (String -> Int) -> String -> Int
forall a b. (a -> b) -> a -> b
$ (Char -> Bool) -> String -> String
forall a. (a -> Bool) -> [a] -> [a]
filter (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
c) String
str

-- | Take last n elements of a list, from:
--   <http://stackoverflow.com/q/17252851/101258>
lastN' :: Int -> [a] -> [a]
lastN' :: Int -> [a] -> [a]
lastN' Int
n [a]
xs = ([a] -> a -> [a]) -> [a] -> [a] -> [a]
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
DL.foldl' ([a] -> a -> [a]
forall a b. a -> b -> a
const ([a] -> a -> [a]) -> ([a] -> [a]) -> [a] -> a -> [a]
forall b c a. (b -> c) -> (a -> b) -> a -> c
.Int -> [a] -> [a]
forall a. Int -> [a] -> [a]
drop Int
1) [a]
xs (Int -> [a] -> [a]
forall a. Int -> [a] -> [a]
drop Int
n [a]
xs)